├── .classpath
├── .gitignore
├── .project
├── AndroidManifest.xml
├── LICENSE
├── README.md
├── create_javadocs.sh
├── default.properties
├── javadocs
├── allclasses-frame.html
├── allclasses-noframe.html
├── com
│ └── jwetherell
│ │ └── motion_detection
│ │ ├── GlobalData.html
│ │ ├── MotionDetectionActivity.html
│ │ ├── Preferences.html
│ │ ├── R.attr.html
│ │ ├── R.drawable.html
│ │ ├── R.html
│ │ ├── R.id.html
│ │ ├── R.layout.html
│ │ ├── R.string.html
│ │ ├── SensorsActivity.html
│ │ ├── data
│ │ ├── GlobalData.html
│ │ ├── Preferences.html
│ │ ├── package-frame.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── data2
│ │ ├── GlobalData.html
│ │ ├── Preferences.html
│ │ ├── package-frame.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── detection
│ │ ├── AggregateLumaMotionDetection.html
│ │ ├── Comparer.html
│ │ ├── IMotionDetection.html
│ │ ├── LumaMotionDetection.html
│ │ ├── RgbMotionDetection.html
│ │ ├── State.html
│ │ ├── package-frame.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── image
│ │ ├── ImageProcessing.html
│ │ ├── package-frame.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── package-frame.html
│ │ ├── package-summary.html
│ │ ├── package-tree.html
│ │ └── preferences
│ │ ├── Preferences.html
│ │ ├── package-frame.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
├── constant-values.html
├── deprecated-list.html
├── help-doc.html
├── index-all.html
├── index.html
├── overview-frame.html
├── overview-summary.html
├── overview-tree.html
├── package-list
├── resources
│ └── inherit.gif
└── stylesheet.css
├── project.properties
├── res
├── drawable-hdpi
│ └── icon.png
├── drawable-ldpi
│ └── icon.png
├── drawable-mdpi
│ └── icon.png
├── layout
│ └── main.xml
└── values
│ └── strings.xml
└── src
└── com
└── jwetherell
└── motion_detection
├── MotionDetectionActivity.java
├── SensorsActivity.java
├── data
├── GlobalData.java
└── Preferences.java
├── detection
├── AggregateLumaMotionDetection.java
├── Comparer.java
├── IMotionDetection.java
├── LumaMotionDetection.java
├── RgbMotionDetection.java
└── State.java
└── image
└── ImageProcessing.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /bin
2 | /gen
3 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndroidMotionDetection
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | android-motion-detection
2 | ========================
3 |
4 | Android code to detection motion from by comparing two pictures.
5 |
6 | ## Introduction
7 |
8 | Android code to detection motion from by comparing two pictures. It comes with an Activity that initializes a camera and grabs two pictures and compares them.
9 |
10 | * Created by Justin Wetherell
11 | * For questions use: http://groups.google.com/forum/#!forum/android-motion-detection
12 | * Google: http://code.google.com/p/android-motion-detection
13 | * Github: http://github.com/phishman3579/android-motion-detection
14 | * LinkedIn: http://www.linkedin.com/in/phishman3579
15 | * E-mail: phishman3579@gmail.com
16 | * Twitter: http://twitter.com/phishman3579
17 |
18 | ## Support me with a donation
19 |
20 |
21 |
22 | ## Details
23 |
24 | You essentially have to override an onPreviewFrame(byte[] data, Camera cam) method and convert from the default YUV to RGB:
25 |
26 | int[] rgb = ImageProcessing.decodeYUV420SPtoRGB(data, width, height);
27 |
28 | Create an object which you'll use for motion detection code:
29 |
30 | IMotionDetection detector = new RgbMotionDetection();
31 |
32 | Call the detect() method passing in the parameters obtained above.
33 |
34 | boolean detected = detector.detect(rgb, width, height)
35 |
36 | If the boolean "detected" variable is true then it has detected motion.
37 |
38 | The RGB detection code is located in RgbMotionDetection.java class. The image processing code is located in ImageProcessing.java static class. The Activity to tie it all together is in MotionDetectionActivity.java.
39 |
40 | I have created a MotionDetection class that detects motion comparing RGB values called RgbMotionDetection.java, a class that detects motion comparing Luminance values called LumaMotionDetection.java, and a class that detects motion comparing avergae Luminance values in regions called AggregateLumaMotionDetection.java.
41 |
--------------------------------------------------------------------------------
/create_javadocs.sh:
--------------------------------------------------------------------------------
1 | #1/bin/bash
2 |
3 | javadoc -author -linkoffline http://d.android.com/reference file:/usr/local/android-sdk-linux_86/docs/reference -classpath /usr/local/android-sdk-linux_86/platforms/android-4/android.jar -d javadocs/ -sourcepath `find . -name *.java`
4 |
--------------------------------------------------------------------------------
/default.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "build.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-7
12 |
--------------------------------------------------------------------------------
/javadocs/allclasses-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | All Classes
7 |
8 |
9 |
10 |
11 | All Classes
12 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/javadocs/allclasses-noframe.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | All Classes
7 |
8 |
9 |
10 |
11 | All Classes
12 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/R.attr.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | R.attr
8 |
9 |
10 |
11 |
12 |
13 |
14 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | com.jwetherell.motion_detection
91 |
92 | Class R.attr
93 |
94 | java.lang.Object
95 | com.jwetherell.motion_detection.R.attr
96 |
97 |
98 | Enclosing class: R
99 |
100 |
101 |
102 | public static final class R.attr extends Object
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | Constructor Summary
117 |
118 |
119 | R.attr ()
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 | Method Summary
133 |
134 |
135 |
136 |
137 |
138 | Methods inherited from class java.lang.Object
139 |
140 |
141 | clone , equals , finalize , getClass , hashCode , notify , notifyAll , toString , wait , wait , wait
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 | Constructor Detail
154 |
155 |
156 |
157 |
158 | R.attr
159 |
160 | public R.attr ()
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/data/GlobalData.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | GlobalData
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
37 |
41 |
45 |
48 |
49 |
59 |
60 |
61 |
62 | SUMMARY:
63 | NESTED |
64 | FIELD |
65 | CONSTR |
66 | METHOD
67 |
68 |
69 | DETAIL:
70 | FIELD |
71 | CONSTR |
72 | METHOD
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
84 |
85 |
86 | java.lang.Object
87 |
88 |
89 | com.jwetherell.motion_detection.data.GlobalData
90 |
91 |
92 |
93 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | Method Summary
115 |
116 | Methods
117 |
118 | Modifier and Type
119 | Method and Description
120 |
121 |
122 | static boolean
123 | isPhoneInMotion ()
124 |
125 |
126 | static void
127 | setPhoneInMotion (boolean bool)
128 |
129 |
130 |
131 |
132 |
133 |
134 | Methods inherited from class java.lang.Object
135 | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
192 |
193 |
197 |
201 |
204 |
205 |
215 |
216 |
217 |
218 | SUMMARY:
219 | NESTED |
220 | FIELD |
221 | CONSTR |
222 | METHOD
223 |
224 |
225 | DETAIL:
226 | FIELD |
227 | CONSTR |
228 | METHOD
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/data/Preferences.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Preferences
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
37 |
41 |
45 |
48 |
49 |
59 |
60 |
61 |
62 | SUMMARY:
63 | NESTED |
64 | FIELD |
65 | CONSTR |
66 | METHOD
67 |
68 |
69 | DETAIL:
70 | FIELD |
71 | CONSTR |
72 | METHOD
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
84 |
85 |
86 | java.lang.Object
87 |
88 |
89 | com.jwetherell.motion_detection.data.Preferences
90 |
91 |
92 |
93 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | Field Summary
116 |
117 | Fields
118 |
119 | Modifier and Type
120 | Field and Description
121 |
122 |
123 | static int
124 | PICTURE_DELAY
125 |
126 |
127 | static boolean
128 | SAVE_CHANGES
129 |
130 |
131 | static boolean
132 | SAVE_ORIGINAL
133 |
134 |
135 | static boolean
136 | SAVE_PREVIOUS
137 |
138 |
139 | static boolean
140 | USE_LUMA
141 |
142 |
143 | static boolean
144 | USE_RGB
145 |
146 |
147 | static boolean
148 | USE_STATE
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | Method Summary
159 |
160 |
161 |
162 |
163 | Methods inherited from class java.lang.Object
164 | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
266 |
267 |
271 |
275 |
278 |
279 |
289 |
290 |
291 |
292 | SUMMARY:
293 | NESTED |
294 | FIELD |
295 | CONSTR |
296 | METHOD
297 |
298 |
299 | DETAIL:
300 | FIELD |
301 | CONSTR |
302 | METHOD
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/data/package-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.jwetherell.motion_detection.data
7 |
8 |
9 |
10 |
11 |
12 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/data/package-summary.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.jwetherell.motion_detection.data
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
63 |
64 |
67 |
68 |
69 |
70 |
71 | Class Summary
72 |
73 | Class
74 | Description
75 |
76 |
77 |
78 | GlobalData
79 |
80 | This class is used to store global data.
81 |
82 |
83 |
84 | Preferences
85 |
86 | This class is used to store preferences on how to decode images and what to
87 | save.
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
111 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/data/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.jwetherell.motion_detection.data Class Hierarchy
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
63 |
64 |
71 |
72 |
Class Hierarchy
73 |
74 | java.lang.Object
75 |
76 | com.jwetherell.motion_detection.data.GlobalData
77 | com.jwetherell.motion_detection.data.Preferences
78 |
79 |
80 |
81 |
82 |
83 |
98 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/data2/package-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | com.jwetherell.motion_detection.data2
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | com.jwetherell.motion_detection.data2
20 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/data2/package-summary.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | com.jwetherell.motion_detection.data2
8 |
9 |
10 |
11 |
12 |
13 |
14 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
77 |
78 |
79 |
80 |
81 |
82 | Package com.jwetherell.motion_detection.data2
83 |
84 |
85 |
86 |
87 |
88 | Class Summary
89 |
90 |
91 | GlobalData
92 | This class is used to store global data.
93 |
94 |
95 | Preferences
96 | This class is used to store preferences on how to decode images and what to save.
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/data2/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | com.jwetherell.motion_detection.data2 Class Hierarchy
8 |
9 |
10 |
11 |
12 |
13 |
14 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | Hierarchy For Package com.jwetherell.motion_detection.data2
84 |
85 |
86 |
87 | Package Hierarchies: All Packages
88 |
89 |
90 | Class Hierarchy
91 |
92 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | PREV
126 | NEXT
127 |
128 | FRAMES
129 | NO FRAMES
130 |
137 |
138 | All Classes
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/detection/IMotionDetection.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | IMotionDetection
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
37 |
41 |
45 |
48 |
49 |
59 |
60 |
61 |
62 | SUMMARY:
63 | NESTED |
64 | FIELD |
65 | CONSTR |
66 | METHOD
67 |
68 |
69 | DETAIL:
70 | FIELD |
71 | CONSTR |
72 | METHOD
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
84 |
85 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | Method Summary
110 |
111 | Methods
112 |
113 | Modifier and Type
114 | Method and Description
115 |
116 |
117 | boolean
118 | detect (int[] data,
119 | int width,
120 | int height)
121 | Detect motion.
122 |
123 |
124 |
125 | int[]
126 | getPrevious ()
127 | Get the previous image in integer array format
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
195 |
196 |
200 |
204 |
207 |
208 |
218 |
219 |
220 |
221 | SUMMARY:
222 | NESTED |
223 | FIELD |
224 | CONSTR |
225 | METHOD
226 |
227 |
228 | DETAIL:
229 | FIELD |
230 | CONSTR |
231 | METHOD
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/detection/package-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.jwetherell.motion_detection.detection
7 |
8 |
9 |
10 |
11 |
12 |
13 |
Interfaces
14 |
17 |
Classes
18 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/detection/package-summary.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.jwetherell.motion_detection.detection
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
63 |
64 |
67 |
68 |
69 |
70 |
71 | Interface Summary
72 |
73 | Interface
74 | Description
75 |
76 |
77 |
78 | IMotionDetection
79 |
80 | This interface is used to represent a class that can detect motion
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | Class Summary
89 |
90 | Class
91 | Description
92 |
93 |
94 |
95 | AggregateLumaMotionDetection
96 |
97 | This class is used to process integer arrays containing luma data and detects
98 | motion using an aggregate map.
99 |
100 |
101 |
102 | Comparer
103 |
104 | This class is adapted from the web site below.
105 |
106 |
107 |
108 | LumaMotionDetection
109 |
110 | This class is used to process integer arrays containing Luma data and detects
111 | motion.
112 |
113 |
114 |
115 | RgbMotionDetection
116 |
117 | This class is used to process integer arrays containing RGB data and detects
118 | motion.
119 |
120 |
121 |
122 | State
123 |
124 | This class is adapted from the web site below.
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
148 |
175 |
176 |
177 |
178 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/detection/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.jwetherell.motion_detection.detection Class Hierarchy
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
63 |
64 |
71 |
72 |
Class Hierarchy
73 |
74 | java.lang.Object
75 |
82 |
83 |
84 |
Interface Hierarchy
85 |
88 |
89 |
90 |
105 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/image/package-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.jwetherell.motion_detection.image
7 |
8 |
9 |
10 |
11 |
12 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/image/package-summary.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.jwetherell.motion_detection.image
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
63 |
64 |
67 |
68 |
69 |
70 |
71 | Class Summary
72 |
73 | Class
74 | Description
75 |
76 |
77 |
78 | ImageProcessing
79 |
80 | This abstract class is used to process images.
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
104 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/image/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.jwetherell.motion_detection.image Class Hierarchy
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
63 |
64 |
71 |
72 |
Class Hierarchy
73 |
74 | java.lang.Object
75 |
78 |
79 |
80 |
81 |
82 |
97 |
98 |
99 | PREV
100 | NEXT
101 |
102 |
106 |
109 |
110 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/package-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.jwetherell.motion_detection
7 |
8 |
9 |
10 |
11 |
12 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/package-summary.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.jwetherell.motion_detection
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
63 |
64 |
67 |
68 |
69 |
70 |
71 | Class Summary
72 |
73 | Class
74 | Description
75 |
76 |
77 |
78 | SensorsActivity
79 |
80 | This class extends Activity and processes sensor data and location data.
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
104 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.jwetherell.motion_detection Class Hierarchy
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
63 |
64 |
71 |
72 |
Class Hierarchy
73 |
74 | java.lang.Object
75 |
76 | Activity
77 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
101 |
102 |
103 | PREV
104 | NEXT
105 |
106 |
110 |
113 |
114 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/preferences/package-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | com.jwetherell.motion_detection.preferences
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | com.jwetherell.motion_detection.preferences
20 |
21 |
22 |
23 | Classes
24 |
25 |
26 | Preferences
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/preferences/package-summary.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | com.jwetherell.motion_detection.preferences
8 |
9 |
10 |
11 |
12 |
13 |
14 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
77 |
78 |
79 |
80 |
81 |
82 | Package com.jwetherell.motion_detection.preferences
83 |
84 |
85 |
86 |
87 |
88 | Class Summary
89 |
90 |
91 | Preferences
92 | This class is used to store preferences on how to decode images and what to save.
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | PREV PACKAGE
130 | NEXT PACKAGE
131 |
132 | FRAMES
133 | NO FRAMES
134 |
141 |
142 | All Classes
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
--------------------------------------------------------------------------------
/javadocs/com/jwetherell/motion_detection/preferences/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | com.jwetherell.motion_detection.preferences Class Hierarchy
8 |
9 |
10 |
11 |
12 |
13 |
14 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | PREV
58 | NEXT
59 |
60 | FRAMES
61 | NO FRAMES
62 |
69 |
70 | All Classes
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | Hierarchy For Package com.jwetherell.motion_detection.preferences
84 |
85 |
86 |
87 | Package Hierarchies: All Packages
88 |
89 |
90 | Class Hierarchy
91 |
92 |
93 | java.lang.Object
94 | com.jwetherell.motion_detection.preferences.Preferences
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | PREV
126 | NEXT
127 |
128 | FRAMES
129 | NO FRAMES
130 |
137 |
138 | All Classes
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/javadocs/constant-values.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Constant Field Values
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
63 |
64 |
71 |
72 |
73 |
74 |
com.jwetherell.*
75 |
76 |
77 |
78 | com.jwetherell.motion_detection.image.ImageProcessing
79 |
80 | Modifier and Type
81 | Constant Field
82 | Value
83 |
84 |
85 |
86 |
87 |
88 | public static final int
89 | A
90 | 0
91 |
92 |
93 |
94 |
95 | public static final int
96 | B
97 | 3
98 |
99 |
100 |
101 |
102 | public static final int
103 | G
104 | 2
105 |
106 |
107 |
108 |
109 | public static final int
110 | H
111 | 0
112 |
113 |
114 |
115 |
116 | public static final int
117 | L
118 | 2
119 |
120 |
121 |
122 |
123 | public static final int
124 | R
125 | 1
126 |
127 |
128 |
129 |
130 | public static final int
131 | S
132 | 1
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
155 |
156 |
157 | PREV
158 | NEXT
159 |
160 |
164 |
167 |
168 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
--------------------------------------------------------------------------------
/javadocs/deprecated-list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Deprecated List
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
63 |
64 |
68 |
69 |
84 |
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/javadocs/help-doc.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | API Help
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
63 |
64 |
68 |
69 |
70 |
71 | Overview
72 | The Overview page is the front page of this API document and provides a list of all packages with a summary for each. This page can also contain an overall description of the set of packages.
73 |
74 |
75 | Package
76 | Each package has a page that contains a list of its classes and interfaces, with a summary for each. This page can contain four categories:
77 |
78 | Interfaces (italic)
79 | Classes
80 | Enums
81 | Exceptions
82 | Errors
83 | Annotation Types
84 |
85 |
86 |
87 | Class/Interface
88 | Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:
89 |
90 | Class inheritance diagram
91 | Direct Subclasses
92 | All Known Subinterfaces
93 | All Known Implementing Classes
94 | Class/interface declaration
95 | Class/interface description
96 |
97 |
98 | Nested Class Summary
99 | Field Summary
100 | Constructor Summary
101 | Method Summary
102 |
103 |
104 | Field Detail
105 | Constructor Detail
106 | Method Detail
107 |
108 | Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.
109 |
110 |
111 | Annotation Type
112 | Each annotation type has its own separate page with the following sections:
113 |
114 | Annotation Type declaration
115 | Annotation Type description
116 | Required Element Summary
117 | Optional Element Summary
118 | Element Detail
119 |
120 |
121 |
122 | Enum
123 | Each enum has its own separate page with the following sections:
124 |
125 | Enum declaration
126 | Enum description
127 | Enum Constant Summary
128 | Enum Constant Detail
129 |
130 |
131 |
132 | Tree (Class Hierarchy)
133 | There is a Class Hierarchy page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. The classes are organized by inheritance structure starting with java.lang.Object
. The interfaces do not inherit from java.lang.Object
.
134 |
135 | When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.
136 | When viewing a particular package, class or interface page, clicking "Tree" displays the hierarchy for only that package.
137 |
138 |
139 |
140 | Deprecated API
141 | The Deprecated API page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.
142 |
143 |
144 | Index
145 | The Index contains an alphabetic list of all classes, interfaces, constructors, methods, and fields.
146 |
147 |
148 | Prev/Next
149 | These links take you to the next or previous class, interface, package, or related page.
150 |
151 |
152 | Frames/No Frames
153 | These links show and hide the HTML frames. All pages are available with or without frames.
154 |
155 |
156 | Serialized Form
157 | Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description.
158 |
159 |
160 | Constant Field Values
161 | The <a href="constant-values.html">Constant Field Values</a> page lists the static final fields and their values.
162 |
163 |
164 |
This help file applies to API documentation generated using the standard doclet.
165 |
166 |
181 |
182 |
183 | PREV
184 | NEXT
185 |
186 |
190 |
193 |
194 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
--------------------------------------------------------------------------------
/javadocs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Generated Documentation (Untitled)
7 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | JavaScript is disabled on your browser.
62 |
63 | Frame Alert
64 | This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
65 | Link toNon-frame version.
66 |
67 |
68 |
--------------------------------------------------------------------------------
/javadocs/overview-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Overview List
7 |
8 |
9 |
10 |
11 |
12 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/javadocs/overview-summary.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Overview
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
63 |
64 |
91 |
92 |
107 |
108 |
109 | PREV
110 | NEXT
111 |
112 |
116 |
119 |
120 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/javadocs/overview-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Class Hierarchy
7 |
8 |
9 |
10 |
11 |
17 |
18 | JavaScript is disabled on your browser.
19 |
20 |
21 |
36 |
63 |
64 |
74 |
75 |
Class Hierarchy
76 |
77 | java.lang.Object
78 |
93 |
94 |
95 |
Interface Hierarchy
96 |
99 |
100 |
101 |
116 |
117 |
118 | PREV
119 | NEXT
120 |
121 |
125 |
128 |
129 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/javadocs/package-list:
--------------------------------------------------------------------------------
1 | com.jwetherell.motion_detection
2 | com.jwetherell.motion_detection.data
3 | com.jwetherell.motion_detection.detection
4 | com.jwetherell.motion_detection.image
5 |
--------------------------------------------------------------------------------
/javadocs/resources/inherit.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phishman3579/android-motion-detection/07b246ac742f01a649163c27b79099bd7118d20b/javadocs/resources/inherit.gif
--------------------------------------------------------------------------------
/javadocs/stylesheet.css:
--------------------------------------------------------------------------------
1 | /* Javadoc style sheet */
2 |
3 | /* Define colors, fonts and other style attributes here to override the defaults */
4 |
5 | /* Page background color */
6 | body { background-color: #FFFFFF; color:#000000 }
7 |
8 | /* Headings */
9 | h1 { font-size: 145% }
10 |
11 | /* Table colors */
12 | .TableHeadingColor { background: #CCCCFF; color:#000000 } /* Dark mauve */
13 | .TableSubHeadingColor { background: #EEEEFF; color:#000000 } /* Light mauve */
14 | .TableRowColor { background: #FFFFFF; color:#000000 } /* White */
15 |
16 | /* Font used in left-hand frame lists */
17 | .FrameTitleFont { font-size: 100%; font-family: Helvetica, Arial, sans-serif; color:#000000 }
18 | .FrameHeadingFont { font-size: 90%; font-family: Helvetica, Arial, sans-serif; color:#000000 }
19 | .FrameItemFont { font-size: 90%; font-family: Helvetica, Arial, sans-serif; color:#000000 }
20 |
21 | /* Navigation bar fonts and colors */
22 | .NavBarCell1 { background-color:#EEEEFF; color:#000000} /* Light mauve */
23 | .NavBarCell1Rev { background-color:#00008B; color:#FFFFFF} /* Dark Blue */
24 | .NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;color:#000000;}
25 | .NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;color:#FFFFFF;}
26 |
27 | .NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF; color:#000000}
28 | .NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF; color:#000000}
29 |
30 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system use,
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 |
10 | # Project target.
11 | target=android-7
12 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phishman3579/android-motion-detection/07b246ac742f01a649163c27b79099bd7118d20b/res/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-ldpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phishman3579/android-motion-detection/07b246ac742f01a649163c27b79099bd7118d20b/res/drawable-ldpi/icon.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phishman3579/android-motion-detection/07b246ac742f01a649163c27b79099bd7118d20b/res/drawable-mdpi/icon.png
--------------------------------------------------------------------------------
/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | MotionDetection
4 |
5 |
--------------------------------------------------------------------------------
/src/com/jwetherell/motion_detection/MotionDetectionActivity.java:
--------------------------------------------------------------------------------
1 | package com.jwetherell.motion_detection;
2 |
3 | import java.io.File;
4 | import java.io.FileOutputStream;
5 | import java.util.concurrent.atomic.AtomicBoolean;
6 |
7 | import com.jwetherell.motion_detection.data.GlobalData;
8 | import com.jwetherell.motion_detection.data.Preferences;
9 | import com.jwetherell.motion_detection.detection.AggregateLumaMotionDetection;
10 | import com.jwetherell.motion_detection.detection.IMotionDetection;
11 | import com.jwetherell.motion_detection.detection.LumaMotionDetection;
12 | import com.jwetherell.motion_detection.detection.RgbMotionDetection;
13 | import com.jwetherell.motion_detection.image.ImageProcessing;
14 |
15 | import android.content.res.Configuration;
16 | import android.graphics.Bitmap;
17 | import android.hardware.Camera;
18 | import android.hardware.Camera.PreviewCallback;
19 | import android.os.AsyncTask;
20 | import android.os.Bundle;
21 | import android.os.Environment;
22 | import android.os.Looper;
23 | import android.util.Log;
24 | import android.view.SurfaceHolder;
25 | import android.view.SurfaceView;
26 |
27 |
28 | /**
29 | * This class extends Activity to handle a picture preview, process the frame
30 | * for motion, and then save the file to the SD card.
31 | *
32 | * @author Justin Wetherell
33 | */
34 | public class MotionDetectionActivity extends SensorsActivity {
35 |
36 | private static final String TAG = "MotionDetectionActivity";
37 |
38 | private static SurfaceView preview = null;
39 | private static SurfaceHolder previewHolder = null;
40 | private static Camera camera = null;
41 | private static boolean inPreview = false;
42 | private static long mReferenceTime = 0;
43 | private static IMotionDetection detector = null;
44 |
45 | private static volatile AtomicBoolean processing = new AtomicBoolean(false);
46 |
47 | /**
48 | * {@inheritDoc}
49 | */
50 | @Override
51 | public void onCreate(Bundle savedInstanceState) {
52 | super.onCreate(savedInstanceState);
53 | setContentView(R.layout.main);
54 |
55 | preview = (SurfaceView) findViewById(R.id.preview);
56 | previewHolder = preview.getHolder();
57 | previewHolder.addCallback(surfaceCallback);
58 | previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
59 |
60 | if (Preferences.USE_RGB) {
61 | detector = new RgbMotionDetection();
62 | } else if (Preferences.USE_LUMA) {
63 | detector = new LumaMotionDetection();
64 | } else {
65 | // Using State based (aggregate map)
66 | detector = new AggregateLumaMotionDetection();
67 | }
68 | }
69 |
70 | /**
71 | * {@inheritDoc}
72 | */
73 | @Override
74 | public void onConfigurationChanged(Configuration newConfig) {
75 | super.onConfigurationChanged(newConfig);
76 | }
77 |
78 | /**
79 | * {@inheritDoc}
80 | */
81 | @Override
82 | public void onPause() {
83 | super.onPause();
84 |
85 | camera.setPreviewCallback(null);
86 | if (inPreview) camera.stopPreview();
87 | inPreview = false;
88 | camera.release();
89 | camera = null;
90 | }
91 |
92 | /**
93 | * {@inheritDoc}
94 | */
95 | @Override
96 | public void onResume() {
97 | super.onResume();
98 |
99 | camera = Camera.open();
100 | }
101 |
102 | private PreviewCallback previewCallback = new PreviewCallback() {
103 |
104 | /**
105 | * {@inheritDoc}
106 | */
107 | @Override
108 | public void onPreviewFrame(byte[] data, Camera cam) {
109 | if (data == null) return;
110 | Camera.Size size = cam.getParameters().getPreviewSize();
111 | if (size == null) return;
112 |
113 | if (!GlobalData.isPhoneInMotion()) {
114 | DetectionThread thread = new DetectionThread(data, size.width, size.height);
115 | thread.start();
116 | }
117 | }
118 | };
119 |
120 | private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
121 |
122 | /**
123 | * {@inheritDoc}
124 | */
125 | @Override
126 | public void surfaceCreated(SurfaceHolder holder) {
127 | try {
128 | camera.setPreviewDisplay(previewHolder);
129 | camera.setPreviewCallback(previewCallback);
130 | } catch (Throwable t) {
131 | Log.e("PreviewDemo-surfaceCallback", "Exception in setPreviewDisplay()", t);
132 | }
133 | }
134 |
135 | /**
136 | * {@inheritDoc}
137 | */
138 | @Override
139 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
140 | Camera.Parameters parameters = camera.getParameters();
141 | Camera.Size size = getBestPreviewSize(width, height, parameters);
142 | if (size != null) {
143 | parameters.setPreviewSize(size.width, size.height);
144 | Log.d(TAG, "Using width=" + size.width + " height=" + size.height);
145 | }
146 | camera.setParameters(parameters);
147 | camera.startPreview();
148 | inPreview = true;
149 | }
150 |
151 | /**
152 | * {@inheritDoc}
153 | */
154 | @Override
155 | public void surfaceDestroyed(SurfaceHolder holder) {
156 | // Ignore
157 | }
158 | };
159 |
160 | private static Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
161 | Camera.Size result = null;
162 |
163 | for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
164 | if (size.width <= width && size.height <= height) {
165 | if (result == null) {
166 | result = size;
167 | } else {
168 | int resultArea = result.width * result.height;
169 | int newArea = size.width * size.height;
170 |
171 | if (newArea > resultArea) result = size;
172 | }
173 | }
174 | }
175 |
176 | return result;
177 | }
178 |
179 | private static final class DetectionThread extends Thread {
180 |
181 | private byte[] data;
182 | private int width;
183 | private int height;
184 |
185 | public DetectionThread(byte[] data, int width, int height) {
186 | this.data = data;
187 | this.width = width;
188 | this.height = height;
189 | }
190 |
191 | /**
192 | * {@inheritDoc}
193 | */
194 | @Override
195 | public void run() {
196 | if (!processing.compareAndSet(false, true)) return;
197 |
198 | // Log.d(TAG, "BEGIN PROCESSING...");
199 | try {
200 | // Previous frame
201 | int[] pre = null;
202 | if (Preferences.SAVE_PREVIOUS) pre = detector.getPrevious();
203 |
204 | // Current frame (with changes)
205 | // long bConversion = System.currentTimeMillis();
206 | int[] img = null;
207 | if (Preferences.USE_RGB) {
208 | img = ImageProcessing.decodeYUV420SPtoRGB(data, width, height);
209 | } else {
210 | img = ImageProcessing.decodeYUV420SPtoLuma(data, width, height);
211 | }
212 | // long aConversion = System.currentTimeMillis();
213 | // Log.d(TAG, "Converstion="+(aConversion-bConversion));
214 |
215 | // Current frame (without changes)
216 | int[] org = null;
217 | if (Preferences.SAVE_ORIGINAL && img != null) org = img.clone();
218 |
219 | if (img != null && detector.detect(img, width, height)) {
220 | // The delay is necessary to avoid taking a picture while in
221 | // the
222 | // middle of taking another. This problem can causes some
223 | // phones
224 | // to reboot.
225 | long now = System.currentTimeMillis();
226 | if (now > (mReferenceTime + Preferences.PICTURE_DELAY)) {
227 | mReferenceTime = now;
228 |
229 | Bitmap previous = null;
230 | if (Preferences.SAVE_PREVIOUS && pre != null) {
231 | if (Preferences.USE_RGB) previous = ImageProcessing.rgbToBitmap(pre, width, height);
232 | else previous = ImageProcessing.lumaToGreyscale(pre, width, height);
233 | }
234 |
235 | Bitmap original = null;
236 | if (Preferences.SAVE_ORIGINAL && org != null) {
237 | if (Preferences.USE_RGB) original = ImageProcessing.rgbToBitmap(org, width, height);
238 | else original = ImageProcessing.lumaToGreyscale(org, width, height);
239 | }
240 |
241 | Bitmap bitmap = null;
242 | if (Preferences.SAVE_CHANGES) {
243 | if (Preferences.USE_RGB) bitmap = ImageProcessing.rgbToBitmap(img, width, height);
244 | else bitmap = ImageProcessing.lumaToGreyscale(img, width, height);
245 | }
246 |
247 | Log.i(TAG, "Saving.. previous=" + previous + " original=" + original + " bitmap=" + bitmap);
248 | Looper.prepare();
249 | new SavePhotoTask().execute(previous, original, bitmap);
250 | } else {
251 | Log.i(TAG, "Not taking picture because not enough time has passed since the creation of the Surface");
252 | }
253 | }
254 | } catch (Exception e) {
255 | e.printStackTrace();
256 | } finally {
257 | processing.set(false);
258 | }
259 | // Log.d(TAG, "END PROCESSING...");
260 |
261 | processing.set(false);
262 | }
263 | };
264 |
265 | private static final class SavePhotoTask extends AsyncTask {
266 |
267 | /**
268 | * {@inheritDoc}
269 | */
270 | @Override
271 | protected Integer doInBackground(Bitmap... data) {
272 | for (int i = 0; i < data.length; i++) {
273 | Bitmap bitmap = data[i];
274 | String name = String.valueOf(System.currentTimeMillis());
275 | if (bitmap != null) save(name, bitmap);
276 | }
277 | return 1;
278 | }
279 |
280 | private void save(String name, Bitmap bitmap) {
281 | File photo = new File(Environment.getExternalStorageDirectory(), name + ".jpg");
282 | if (photo.exists()) photo.delete();
283 |
284 | try {
285 | FileOutputStream fos = new FileOutputStream(photo.getPath());
286 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
287 | fos.close();
288 | } catch (java.io.IOException e) {
289 | Log.e("PictureDemo", "Exception in photoCallback", e);
290 | }
291 | }
292 | }
293 | }
--------------------------------------------------------------------------------
/src/com/jwetherell/motion_detection/SensorsActivity.java:
--------------------------------------------------------------------------------
1 | package com.jwetherell.motion_detection;
2 |
3 | import java.util.List;
4 | import java.util.concurrent.atomic.AtomicBoolean;
5 |
6 | import com.jwetherell.motion_detection.data.GlobalData;
7 |
8 | import android.app.Activity;
9 | import android.hardware.Sensor;
10 | import android.hardware.SensorEvent;
11 | import android.hardware.SensorEventListener;
12 | import android.hardware.SensorManager;
13 | import android.os.Bundle;
14 | import android.util.Log;
15 |
16 |
17 | /**
18 | * This class extends Activity and processes sensor data and location data. It
19 | * is used to detect when the phone is in motion, so we do not try to detect
20 | * motion.
21 | *
22 | * @author Justin Wetherell
23 | */
24 | public class SensorsActivity extends Activity implements SensorEventListener {
25 |
26 | private static final String TAG = "SensorsActivity";
27 | private static final AtomicBoolean computing = new AtomicBoolean(false);
28 |
29 | private static final float grav[] = new float[3]; // Gravity (a.k.a
30 | // accelerometer data)
31 | private static final float mag[] = new float[3]; // Magnetic
32 |
33 | private static final float gravThreshold = 0.5f;
34 | private static final float magThreshold = 1.0f;
35 |
36 | private static SensorManager sensorMgr = null;
37 | private static List sensors = null;
38 | private static Sensor sensorGrav = null;
39 | private static Sensor sensorMag = null;
40 |
41 | private static float prevGrav = 0.0f;
42 | private static float prevMag = 0.0f;
43 |
44 | /**
45 | * {@inheritDoc}
46 | */
47 | @Override
48 | public void onCreate(Bundle savedInstanceState) {
49 | super.onCreate(savedInstanceState);
50 | }
51 |
52 | /**
53 | * {@inheritDoc}
54 | */
55 | @Override
56 | public void onDestroy() {
57 | super.onDestroy();
58 | }
59 |
60 | /**
61 | * {@inheritDoc}
62 | */
63 | @Override
64 | public void onStart() {
65 | super.onStart();
66 |
67 | try {
68 | sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
69 |
70 | sensors = sensorMgr.getSensorList(Sensor.TYPE_ACCELEROMETER);
71 | if (sensors.size() > 0) sensorGrav = sensors.get(0);
72 |
73 | sensors = sensorMgr.getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
74 | if (sensors.size() > 0) sensorMag = sensors.get(0);
75 |
76 | sensorMgr.registerListener(this, sensorGrav, SensorManager.SENSOR_DELAY_NORMAL);
77 | sensorMgr.registerListener(this, sensorMag, SensorManager.SENSOR_DELAY_NORMAL);
78 | } catch (Exception ex1) {
79 | try {
80 | if (sensorMgr != null) {
81 | sensorMgr.unregisterListener(this, sensorGrav);
82 | sensorMgr.unregisterListener(this, sensorMag);
83 | sensorMgr = null;
84 | }
85 | } catch (Exception ex2) {
86 | ex2.printStackTrace();
87 | }
88 | }
89 | }
90 |
91 | /**
92 | * {@inheritDoc}
93 | */
94 | @Override
95 | public void onStop() {
96 | super.onStop();
97 |
98 | try {
99 | try {
100 | sensorMgr.unregisterListener(this, sensorGrav);
101 | } catch (Exception ex) {
102 | ex.printStackTrace();
103 | }
104 | try {
105 | sensorMgr.unregisterListener(this, sensorMag);
106 | } catch (Exception ex) {
107 | ex.printStackTrace();
108 | }
109 | sensorMgr = null;
110 | } catch (Exception ex) {
111 | ex.printStackTrace();
112 | }
113 | }
114 |
115 | /**
116 | * {@inheritDoc}
117 | */
118 | @Override
119 | public void onSensorChanged(SensorEvent evt) {
120 | if (!computing.compareAndSet(false, true)) return;
121 |
122 | if (evt.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
123 | grav[0] = evt.values[0];
124 | grav[1] = evt.values[1];
125 | grav[2] = evt.values[2];
126 | } else if (evt.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
127 | mag[0] = evt.values[0];
128 | mag[1] = evt.values[1];
129 | mag[2] = evt.values[2];
130 | }
131 |
132 | float gravity = grav[0] + grav[1] + grav[2];
133 | float magnetic = mag[0] + mag[1] + mag[2];
134 |
135 | float gravDiff = Math.abs(gravity - prevGrav);
136 | float magDiff = Math.abs(magnetic - prevMag);
137 | // Log.i(TAG, "gravDiff="+gravDiff+" magDiff="+magDiff);
138 |
139 | if ((Float.compare(prevGrav, 0.0f) != 0 && Float.compare(prevMag, 0.0f) != 0) && (gravDiff > gravThreshold || magDiff > magThreshold)) {
140 | GlobalData.setPhoneInMotion(true);
141 | } else {
142 | GlobalData.setPhoneInMotion(false);
143 | }
144 |
145 | prevGrav = gravity;
146 | prevMag = magnetic;
147 |
148 | computing.set(false);
149 | }
150 |
151 | /**
152 | * {@inheritDoc}
153 | */
154 | @Override
155 | public void onAccuracyChanged(Sensor sensor, int accuracy) {
156 | if (sensor == null) throw new NullPointerException();
157 |
158 | if (sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD && accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
159 | Log.e(TAG, "Compass data unreliable");
160 | }
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/com/jwetherell/motion_detection/data/GlobalData.java:
--------------------------------------------------------------------------------
1 | package com.jwetherell.motion_detection.data;
2 |
3 | import java.util.concurrent.atomic.AtomicBoolean;
4 |
5 |
6 | /**
7 | * This class is used to store global data.
8 | *
9 | * @author Justin Wetherell
10 | */
11 | public abstract class GlobalData {
12 |
13 | private GlobalData() {
14 | };
15 |
16 | private static final AtomicBoolean phoneInMotion = new AtomicBoolean(false);
17 |
18 | public static boolean isPhoneInMotion() {
19 | return phoneInMotion.get();
20 | }
21 |
22 | public static void setPhoneInMotion(boolean bool) {
23 | phoneInMotion.set(bool);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/com/jwetherell/motion_detection/data/Preferences.java:
--------------------------------------------------------------------------------
1 | package com.jwetherell.motion_detection.data;
2 |
3 | /**
4 | * This class is used to store preferences on how to decode images and what to
5 | * save.
6 | *
7 | * @author Justin Wetherell
8 | */
9 | public abstract class Preferences {
10 |
11 | private Preferences() {
12 | }
13 |
14 | // Which motion detection to use
15 | public static boolean USE_RGB = true;
16 | public static boolean USE_LUMA = false;
17 | public static boolean USE_STATE = false;
18 |
19 | // Which photos to save
20 | public static boolean SAVE_PREVIOUS = false;
21 | public static boolean SAVE_ORIGINAL = true;
22 | public static boolean SAVE_CHANGES = true;
23 |
24 | // Time between saving photos
25 | public static int PICTURE_DELAY = 10000;
26 | }
27 |
--------------------------------------------------------------------------------
/src/com/jwetherell/motion_detection/detection/AggregateLumaMotionDetection.java:
--------------------------------------------------------------------------------
1 | package com.jwetherell.motion_detection.detection;
2 |
3 | //import android.util.Log;
4 |
5 | /**
6 | * This class is used to process integer arrays containing luma data and detects
7 | * motion using an aggregate map.
8 | *
9 | * @author Justin Wetherell
10 | */
11 | public class AggregateLumaMotionDetection implements IMotionDetection {
12 |
13 | // private static final String TAG = "AggregateLumaMotionDetection";
14 |
15 | // Specific settings
16 | private static final int mLeniency = 10; // Difference of aggregate map of
17 | // luma values
18 | private static final int mDebugMode = 2; // State based debug
19 | private static final int mXBoxes = 10; // State based debug
20 | private static final int mYBoxes = 10; // State based debug
21 |
22 | private static int[] mPrevious = null;
23 | private static int mPreviousWidth;
24 | private static int mPreviousHeight;
25 | private static State mPreviousState = null;
26 |
27 | /**
28 | * {@inheritDoc}
29 | */
30 | @Override
31 | public int[] getPrevious() {
32 | return ((mPrevious != null) ? mPrevious.clone() : null);
33 | }
34 |
35 | protected static boolean isDifferent(int[] first, int width, int height) {
36 | if (first == null) throw new NullPointerException();
37 |
38 | if (mPrevious == null) return false;
39 | if (first.length != mPrevious.length) return true;
40 | if (mPreviousWidth != width || mPreviousHeight != height) return true;
41 |
42 | if (mPreviousState == null) {
43 | mPreviousState = new State(mPrevious, mPreviousWidth, mPreviousHeight);
44 | return false;
45 | }
46 |
47 | State state = new State(first, width, height);
48 | Comparer comparer = new Comparer(state, mPreviousState, mXBoxes, mYBoxes, mLeniency, mDebugMode);
49 |
50 | boolean different = comparer.isDifferent();
51 | // String output = "isDifferent="+different;
52 | if (different) {
53 | // Log.e(TAG, output);
54 | comparer.paintDifferences(first);
55 | // } else {
56 | // Log.d(TAG, output);
57 | }
58 |
59 | mPreviousState = state;
60 |
61 | return different;
62 | }
63 |
64 | /**
65 | * Detect motion using aggregate luma values. {@inheritDoc}
66 | */
67 | @Override
68 | public boolean detect(int[] luma, int width, int height) {
69 | if (luma == null) throw new NullPointerException();
70 |
71 | int[] original = luma.clone();
72 |
73 | // Create the "mPrevious" picture, the one that will be used to check
74 | // the next frame against.
75 | if (mPrevious == null) {
76 | mPrevious = original;
77 | mPreviousWidth = width;
78 | mPreviousHeight = height;
79 | // Log.i(TAG, "Creating background image");
80 | }
81 |
82 | // long bDetection = System.currentTimeMillis();
83 | boolean motionDetected = isDifferent(luma, width, height);
84 | // long aDetection = System.currentTimeMillis();
85 | // Log.d(TAG, "Detection "+(aDetection-bDetection));
86 |
87 | // Replace the current image with the previous.
88 | mPrevious = original;
89 | mPreviousWidth = width;
90 | mPreviousHeight = height;
91 |
92 | return motionDetected;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/com/jwetherell/motion_detection/detection/Comparer.java:
--------------------------------------------------------------------------------
1 | package com.jwetherell.motion_detection.detection;
2 |
3 | import android.graphics.Color;
4 |
5 |
6 | /**
7 | * This class is adapted from the web site below. It is used to compare two
8 | * State objects.
9 | * http://mindmeat.blogspot.com/2008/11/java-image-comparison.html
10 | *
11 | * @author Pat Cullen
12 | * @author Justin Wetherell
13 | */
14 | public class Comparer {
15 |
16 | private State state1 = null;
17 | private State state2 = null;
18 | private int xBoxes;
19 | private int yBoxes;
20 | private int xPixelsPerBox;
21 | private int yPixelsPerBox;
22 | private int xLeftOver;
23 | private int yLeftOver;
24 | private int rowWidthInPix;
25 | private int colWidthInPix;
26 | private int leniency;
27 | private int debugMode; // 1: textual indication of change, 2: difference of
28 | // factors
29 |
30 | private int[][] variance = null;
31 | private boolean different = false;
32 |
33 | public Comparer(State s1, State s2, int xBoxes, int yBoxes, int leniency, int debug) {
34 | this.state1 = s1;
35 | this.state2 = s2;
36 |
37 | this.xBoxes = xBoxes;
38 | if (this.xBoxes > s1.getWidth()) this.xBoxes = s1.getWidth();
39 |
40 | this.yBoxes = yBoxes;
41 | if (this.yBoxes > s1.getHeight()) this.yBoxes = s1.getHeight();
42 |
43 | this.leniency = leniency;
44 | this.debugMode = 0;
45 |
46 | // how many points per box
47 | this.xPixelsPerBox = (int) (Math.floor(s1.getWidth() / this.xBoxes));
48 | if (xPixelsPerBox <= 0) xPixelsPerBox = 1;
49 | this.yPixelsPerBox = (int) (Math.floor(s1.getHeight() / this.yBoxes));
50 | if (yPixelsPerBox <= 0) yPixelsPerBox = 1;
51 |
52 | this.xLeftOver = s1.getWidth() - (this.xBoxes * this.xPixelsPerBox);
53 | if (xLeftOver > 0) this.xBoxes++;
54 | yLeftOver = s1.getHeight() - (this.yBoxes * this.yPixelsPerBox);
55 | if (yLeftOver > 0) this.yBoxes++;
56 |
57 | this.rowWidthInPix = (this.xBoxes * xPixelsPerBox) - (xPixelsPerBox - xLeftOver);
58 | this.colWidthInPix = this.xPixelsPerBox;
59 |
60 | this.debugMode = debug;
61 |
62 | this.different = isDifferent(this.state1, this.state2);
63 | }
64 |
65 | /**
66 | * Compare two images and populate the variance variable
67 | *
68 | * @param s1
69 | * State for image one.
70 | * @param s2
71 | * State for image two.
72 | * @return True is the two images are different.
73 | * @throws NullPointerException
74 | * if s1 or s2 is NULL.
75 | */
76 | public boolean isDifferent(State s1, State s2) {
77 | if (s1 == null || s2 == null) throw new NullPointerException();
78 | if (s1.getWidth() != s2.getWidth() || s1.getHeight() != s2.getHeight()) return true;
79 |
80 | // Boxes
81 | this.variance = new int[yBoxes][xBoxes];
82 |
83 | // set to a different by default, if a change is found then flag
84 | // non-match
85 | boolean different = false;
86 | // loop through whole image and compare individual blocks of images
87 | int b1 = 0;
88 | int b2 = 0;
89 | int diff = 0;
90 | for (int y = 0; y < yBoxes; y++) {
91 | for (int x = 0; x < xBoxes; x++) {
92 | b1 = aggregateMapArea(state1.getMap(), x, y);
93 | b2 = aggregateMapArea(state2.getMap(), x, y);
94 | diff = Math.abs(b1 - b2);
95 | variance[y][x] = diff;
96 | // the difference in a certain region has passed the threshold
97 | // value
98 | if (diff > leniency) different = true;
99 | }
100 | }
101 | return different;
102 | }
103 |
104 | private int aggregateMapArea(int[] map, int xBox, int yBox) {
105 | if (map == null) throw new NullPointerException();
106 |
107 | int yPix = yPixelsPerBox;
108 | int xPix = xPixelsPerBox;
109 | if (yBox == (yBoxes - 1) && yLeftOver > 0) yPix = yLeftOver;
110 | if (xBox == (xBoxes - 1) && xLeftOver > 0) xPix = xLeftOver;
111 |
112 | int rowOffset = (yBox * yPixelsPerBox * rowWidthInPix);
113 | int columnOffset = (xBox * colWidthInPix);
114 |
115 | int i = 0;
116 | int iy = 0;
117 | for (int y = 0; y < yPix; y++) {
118 | iy = (y * (xBoxes * xPixelsPerBox)) - (y * (xPixelsPerBox - xLeftOver));
119 | for (int x = 0; x < xPix; x++) {
120 | i += map[rowOffset + columnOffset + iy + x];
121 | }
122 | }
123 |
124 | return (i / (xPix * yPix));
125 | }
126 |
127 | /**
128 | * Given the int array of an image, paint the pixels that are different.
129 | *
130 | * @param data
131 | * int array of an image.
132 | * @throws NullPointerException
133 | * if data int array is NULL.
134 | */
135 | public void paintDifferences(int[] data) {
136 | if (data == null) throw new NullPointerException();
137 |
138 | for (int y = 0; y < yBoxes; y++) {
139 | for (int x = 0; x < xBoxes; x++) {
140 | if (variance[y][x] > leniency) paint(data, x, y, Color.RED);
141 | }
142 | }
143 | }
144 |
145 | private void paint(int[] data, int xBox, int yBox, int color) {
146 | if (data == null) throw new NullPointerException();
147 |
148 | int yPix = yPixelsPerBox;
149 | int xPix = xPixelsPerBox;
150 | if (yBox == (yBoxes - 1) && yLeftOver > 0) yPix = yLeftOver;
151 | if (xBox == (xBoxes - 1) && xLeftOver > 0) xPix = xLeftOver;
152 |
153 | int rowOffset = (yBox * yPixelsPerBox * rowWidthInPix);
154 | int columnOffset = (xBox * colWidthInPix);
155 |
156 | int iy = 0;
157 | for (int y = 0; y < yPix; y++) {
158 | iy = y * (xBoxes * xPixelsPerBox) - (y * (xPixelsPerBox - xLeftOver));
159 | for (int x = 0; x < xPix; x++) {
160 | if (y == 0 || y == (yPix - 1) || x == 0 || x == (xPix - 1)) data[rowOffset + columnOffset + iy + x] = color;
161 | }
162 | }
163 | }
164 |
165 | /**
166 | * Number of X Boxes.
167 | *
168 | * @return int representing the number of X boxes.
169 | */
170 | public int getCompareX() {
171 | return xBoxes;
172 | }
173 |
174 | /**
175 | * Number of Y Boxes.
176 | *
177 | * @return int representing the number of Y boxes.
178 | */
179 | public int getCompareY() {
180 | return yBoxes;
181 | }
182 |
183 | /**
184 | * Leniency of the pixel comparison.
185 | *
186 | * @return int representing the leniency.
187 | */
188 | public int getLeniency() {
189 | return leniency;
190 | }
191 |
192 | /**
193 | * Debug mode of the comparer.
194 | *
195 | * @return int representing the debug mode.
196 | */
197 | public int getDebugMode() {
198 | return debugMode;
199 | }
200 |
201 | /**
202 | * Are the two States different.
203 | *
204 | * @return True is the States are different.
205 | */
206 | public boolean isDifferent() {
207 | return different;
208 | }
209 |
210 | /**
211 | * {@inheritDoc}
212 | */
213 | @Override
214 | public String toString() {
215 | int diff = 0;
216 | StringBuilder output = new StringBuilder();
217 | for (int y = 0; y < yBoxes; y++) {
218 | output.append('|');
219 | for (int x = 0; x < xBoxes; x++) {
220 | diff = variance[y][x];
221 | if (debugMode == 1) output.append((diff > leniency) ? 'X' : ' ');
222 | if (debugMode == 2) output.append(diff + ((x < (xBoxes - 1)) ? "," : ""));
223 | }
224 | output.append("|\n");
225 | }
226 | return output.toString();
227 | }
228 | }
229 |
--------------------------------------------------------------------------------
/src/com/jwetherell/motion_detection/detection/IMotionDetection.java:
--------------------------------------------------------------------------------
1 | package com.jwetherell.motion_detection.detection;
2 |
3 | /**
4 | * This interface is used to represent a class that can detect motion
5 | *
6 | * @author Justin Wetherell
7 | */
8 | public interface IMotionDetection {
9 |
10 | /**
11 | * Get the previous image in integer array format
12 | *
13 | * @return int array of previous image.
14 | */
15 | public int[] getPrevious();
16 |
17 | /**
18 | * Detect motion.
19 | *
20 | * @param data
21 | * integer array representing an image.
22 | * @param width
23 | * Width of the image.
24 | * @param height
25 | * Height of the image.
26 | * @return boolean True is there is motion.
27 | * @throws NullPointerException
28 | * if data integer array is NULL.
29 | */
30 | public boolean detect(int[] data, int width, int height);
31 | }
32 |
--------------------------------------------------------------------------------
/src/com/jwetherell/motion_detection/detection/LumaMotionDetection.java:
--------------------------------------------------------------------------------
1 | package com.jwetherell.motion_detection.detection;
2 |
3 | import android.graphics.Color;
4 |
5 |
6 | //import android.util.Log;
7 |
8 | /**
9 | * This class is used to process integer arrays containing Luma data and detects
10 | * motion.
11 | *
12 | * @author Justin Wetherell
13 | */
14 | public class LumaMotionDetection implements IMotionDetection {
15 |
16 | // private static final String TAG = "LumaMotionDetection";
17 |
18 | // Specific settings
19 | private static final int mPixelThreshold = 50; // Difference in luma value
20 | private static final int mThreshold = 10000; // Number of different pixels
21 |
22 | private static int[] mPrevious = null;
23 | private static int mPreviousWidth = 0;
24 | private static int mPreviousHeight = 0;
25 |
26 | /**
27 | * {@inheritDoc}
28 | */
29 | @Override
30 | public int[] getPrevious() {
31 | return ((mPrevious != null) ? mPrevious.clone() : null);
32 | }
33 |
34 | protected static boolean isDifferent(int[] first, int width, int height) {
35 | if (first == null) throw new NullPointerException();
36 |
37 | if (mPrevious == null) return false;
38 | if (first.length != mPrevious.length) return true;
39 | if (mPreviousWidth != width || mPreviousHeight != height) return true;
40 |
41 | int totDifferentPixels = 0;
42 | for (int i = 0, ij = 0; i < height; i++) {
43 | for (int j = 0; j < width; j++, ij++) {
44 | int pix = (0xff & (first[ij]));
45 | int otherPix = (0xff & (mPrevious[ij]));
46 |
47 | // Catch any pixels that are out of range
48 | if (pix < 0) pix = 0;
49 | if (pix > 255) pix = 255;
50 | if (otherPix < 0) otherPix = 0;
51 | if (otherPix > 255) otherPix = 255;
52 |
53 | if (Math.abs(pix - otherPix) >= mPixelThreshold) {
54 | totDifferentPixels++;
55 | // Paint different pixel red
56 | first[ij] = Color.RED;
57 | }
58 | }
59 | }
60 | if (totDifferentPixels <= 0) totDifferentPixels = 1;
61 | boolean different = totDifferentPixels > mThreshold;
62 | /*
63 | * int size = height * width; int percent =
64 | * 100/(size/totDifferentPixels); String output =
65 | * "Number of different pixels: " + totDifferentPixels + "> " + percent
66 | * + "%"; if (different) { Log.e(TAG, output); } else { Log.d(TAG,
67 | * output); }
68 | */
69 | return different;
70 | }
71 |
72 | /**
73 | * Detect motion using comparing luma values. {@inheritDoc}
74 | */
75 | @Override
76 | public boolean detect(int[] luma, int width, int height) {
77 | if (luma == null) throw new NullPointerException();
78 |
79 | int[] original = luma.clone();
80 |
81 | // Create the "mPrevious" picture, the one that will be used to check
82 | // the next frame against.
83 | if (mPrevious == null) {
84 | mPrevious = original;
85 | mPreviousWidth = width;
86 | mPreviousHeight = height;
87 | // Log.i(TAG, "Creating background image");
88 | return false;
89 | }
90 |
91 | // long bDetection = System.currentTimeMillis();
92 | boolean motionDetected = isDifferent(luma, width, height);
93 | // long aDetection = System.currentTimeMillis();
94 | // Log.d(TAG, "Detection "+(aDetection-bDetection));
95 |
96 | // Replace the current image with the previous.
97 | mPrevious = original;
98 | mPreviousWidth = width;
99 | mPreviousHeight = height;
100 |
101 | return motionDetected;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/com/jwetherell/motion_detection/detection/RgbMotionDetection.java:
--------------------------------------------------------------------------------
1 | package com.jwetherell.motion_detection.detection;
2 |
3 | import android.graphics.Color;
4 |
5 |
6 | //import android.util.Log;
7 |
8 | /**
9 | * This class is used to process integer arrays containing RGB data and detects
10 | * motion.
11 | *
12 | * @author Justin Wetherell
13 | */
14 | public class RgbMotionDetection implements IMotionDetection {
15 |
16 | // private static final String TAG = "RgbMotionDetection";
17 |
18 | // Specific settings
19 | private static final int mPixelThreshold = 50; // Difference in pixel (RGB)
20 | private static final int mThreshold = 10000; // Number of different pixels
21 | // (RGB)
22 |
23 | private static int[] mPrevious = null;
24 | private static int mPreviousWidth = 0;
25 | private static int mPreviousHeight = 0;
26 |
27 | /**
28 | * {@inheritDoc}
29 | */
30 | @Override
31 | public int[] getPrevious() {
32 | return ((mPrevious != null) ? mPrevious.clone() : null);
33 | }
34 |
35 | protected static boolean isDifferent(int[] first, int width, int height) {
36 | if (first == null) throw new NullPointerException();
37 |
38 | if (mPrevious == null) return false;
39 | if (first.length != mPrevious.length) return true;
40 | if (mPreviousWidth != width || mPreviousHeight != height) return true;
41 |
42 | int totDifferentPixels = 0;
43 | for (int i = 0, ij = 0; i < height; i++) {
44 | for (int j = 0; j < width; j++, ij++) {
45 | int pix = (0xff & (first[ij]));
46 | int otherPix = (0xff & (mPrevious[ij]));
47 |
48 | // Catch any pixels that are out of range
49 | if (pix < 0) pix = 0;
50 | if (pix > 255) pix = 255;
51 | if (otherPix < 0) otherPix = 0;
52 | if (otherPix > 255) otherPix = 255;
53 |
54 | if (Math.abs(pix - otherPix) >= mPixelThreshold) {
55 | totDifferentPixels++;
56 | // Paint different pixel red
57 | first[ij] = Color.RED;
58 | }
59 | }
60 | }
61 | if (totDifferentPixels <= 0) totDifferentPixels = 1;
62 | boolean different = totDifferentPixels > mThreshold;
63 | /*
64 | * int size = height * width; int percent =
65 | * 100/(size/totDifferentPixels); String output =
66 | * "Number of different pixels: " + totDifferentPixels + "> " + percent
67 | * + "%"; if (different) { Log.e(TAG, output); } else { Log.d(TAG,
68 | * output); }
69 | */
70 | return different;
71 | }
72 |
73 | /**
74 | * Detect motion comparing RGB pixel values. {@inheritDoc}
75 | */
76 | @Override
77 | public boolean detect(int[] rgb, int width, int height) {
78 | if (rgb == null) throw new NullPointerException();
79 |
80 | int[] original = rgb.clone();
81 |
82 | // Create the "mPrevious" picture, the one that will be used to check
83 | // the next frame against.
84 | if (mPrevious == null) {
85 | mPrevious = original;
86 | mPreviousWidth = width;
87 | mPreviousHeight = height;
88 | // Log.i(TAG, "Creating background image");
89 | return false;
90 | }
91 |
92 | // long bDetection = System.currentTimeMillis();
93 | boolean motionDetected = isDifferent(rgb, width, height);
94 | // long aDetection = System.currentTimeMillis();
95 | // Log.d(TAG, "Detection "+(aDetection-bDetection));
96 |
97 | // Replace the current image with the previous.
98 | mPrevious = original;
99 | mPreviousWidth = width;
100 | mPreviousHeight = height;
101 |
102 | return motionDetected;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/com/jwetherell/motion_detection/detection/State.java:
--------------------------------------------------------------------------------
1 | package com.jwetherell.motion_detection.detection;
2 |
3 | /**
4 | * This class is adapted from the web site below. It creates a state object
5 | * based on the brightness of a RGB image represented by an integer array.
6 | * http://mindmeat.blogspot.com/2008/11/java-image-comparison.html
7 | *
8 | * @author Pat Cullen
9 | * @author Justin Wetherell
10 | */
11 | public class State {
12 |
13 | private int[] map = null;
14 | private int width;
15 | private int height;
16 | private int average;
17 |
18 | public State(int[] data, int width, int height) {
19 | if (data == null) throw new NullPointerException();
20 |
21 | this.map = data.clone();
22 | this.width = width;
23 | this.height = height;
24 |
25 | // build map and stats
26 | this.average = 0;
27 | for (int y = 0, xy = 0; y < this.height; y++) {
28 | for (int x = 0; x < this.width; x++, xy++) {
29 | this.average += data[xy];
30 | }
31 | }
32 | this.average = (this.average / (this.width * this.height));
33 | }
34 |
35 | /**
36 | * Get Map of the State.
37 | *
38 | * @return integer array of the State.
39 | */
40 | public int[] getMap() {
41 | return map;
42 | }
43 |
44 | /**
45 | * Get the width of the State.
46 | *
47 | * @return integer representing the width of the state.
48 | */
49 | public int getWidth() {
50 | return width;
51 | }
52 |
53 | /**
54 | * Get the height of the State.
55 | *
56 | * @return integer representing the height of the state.
57 | */
58 | public int getHeight() {
59 | return height;
60 | }
61 |
62 | /**
63 | * {@inheritDoc}
64 | */
65 | @Override
66 | public String toString() {
67 | StringBuilder output = new StringBuilder();
68 | output.append("h=" + height + " w=" + width + "\n");
69 | for (int y = 0, xy = 0; y < height; y++) {
70 | output.append('|');
71 | for (int x = 0; x < width; x++, xy++) {
72 | output.append(map[xy]);
73 | output.append('|');
74 | }
75 | output.append("\n");
76 | }
77 | return output.toString();
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/com/jwetherell/motion_detection/image/ImageProcessing.java:
--------------------------------------------------------------------------------
1 | package com.jwetherell.motion_detection.image;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Color;
7 | import android.graphics.Matrix;
8 |
9 |
10 | /**
11 | * This abstract class is used to process images.
12 | *
13 | * @author Justin Wetherell
14 | */
15 | public abstract class ImageProcessing {
16 |
17 | public static final int A = 0;
18 | public static final int R = 1;
19 | public static final int G = 2;
20 | public static final int B = 3;
21 |
22 | public static final int H = 0;
23 | public static final int S = 1;
24 | public static final int L = 2;
25 |
26 | private ImageProcessing() {
27 | }
28 |
29 | /**
30 | * Get RGB values from pixel.
31 | *
32 | * @param pixel
33 | * Integer representation of a pixel.
34 | * @return float array of a,r,g,b values.
35 | */
36 | public static float[] getARGB(int pixel) {
37 | int a = (pixel >> 24) & 0xff;
38 | int r = (pixel >> 16) & 0xff;
39 | int g = (pixel >> 8) & 0xff;
40 | int b = (pixel) & 0xff;
41 | return (new float[] { a, r, g, b });
42 | }
43 |
44 | /**
45 | * Get HSL (Hue, Saturation, Luma) from RGB. Note1: H is 0-360 (degrees)
46 | * Note2: S and L are 0-100 (percent)
47 | *
48 | * @param r
49 | * Red value.
50 | * @param g
51 | * Green value.
52 | * @param b
53 | * Blue value.
54 | * @return Integer array representing an HSL pixel.
55 | */
56 | public static int[] convertToHSL(int r, int g, int b) {
57 | float red = r / 255;
58 | float green = g / 255;
59 | float blue = b / 255;
60 |
61 | float minComponent = Math.min(red, Math.min(green, blue));
62 | float maxComponent = Math.max(red, Math.max(green, blue));
63 | float range = maxComponent - minComponent;
64 | float h = 0, s = 0, l = 0;
65 |
66 | l = (maxComponent + minComponent) / 2;
67 |
68 | if (range == 0) { // Monochrome image
69 | h = s = 0;
70 | } else {
71 | s = (l > 0.5) ? range / (2 - range) : range / (maxComponent + minComponent);
72 |
73 | if (red == maxComponent) {
74 | h = (blue - green) / range;
75 | } else if (green == maxComponent) {
76 | h = 2 + (blue - red) / range;
77 | } else if (blue == maxComponent) {
78 | h = 4 + (red - green) / range;
79 | }
80 | }
81 |
82 | // convert to 0-360 (degrees)
83 | h *= 60;
84 | if (h < 0) h += 360;
85 |
86 | // convert to 0-100 (percent)
87 | s *= 100;
88 | l *= 100;
89 |
90 | // Since they were converted from float to int
91 | return (new int[] { (int) h, (int) s, (int) l });
92 | }
93 |
94 | /**
95 | * Decode a YUV420SP image to Luma.
96 | *
97 | * @param yuv420sp
98 | * Byte array representing a YUV420SP image.
99 | * @param width
100 | * Width of the image.
101 | * @param height
102 | * Height of the image.
103 | * @return Integer array representing the Luma image.
104 | * @throws NullPointerException
105 | * if yuv420sp byte array is NULL.
106 | */
107 | public static int[] decodeYUV420SPtoLuma(byte[] yuv420sp, int width, int height) {
108 | if (yuv420sp == null) throw new NullPointerException();
109 |
110 | final int frameSize = width * height;
111 | int[] hsl = new int[frameSize];
112 |
113 | for (int j = 0, yp = 0; j < height; j++) {
114 | for (int i = 0; i < width; i++, yp++) {
115 | int y = (0xff & (yuv420sp[yp])) - 16;
116 | if (y < 0) y = 0;
117 | hsl[yp] = y;
118 | }
119 | }
120 | return hsl;
121 | }
122 |
123 | /**
124 | * Decode a YUV420SP image to RGB.
125 | *
126 | * @param yuv420sp
127 | * Byte array representing a YUV420SP image.
128 | * @param width
129 | * Width of the image.
130 | * @param height
131 | * Height of the image.
132 | * @return Integer array representing the RGB image.
133 | * @throws NullPointerException
134 | * if yuv420sp byte array is NULL.
135 | */
136 | public static int[] decodeYUV420SPtoRGB(byte[] yuv420sp, int width, int height) {
137 | if (yuv420sp == null) throw new NullPointerException();
138 |
139 | final int frameSize = width * height;
140 | int[] rgb = new int[frameSize];
141 |
142 | for (int j = 0, yp = 0; j < height; j++) {
143 | int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
144 | for (int i = 0; i < width; i++, yp++) {
145 | int y = (0xff & (yuv420sp[yp])) - 16;
146 | if (y < 0) y = 0;
147 | if ((i & 1) == 0) {
148 | v = (0xff & yuv420sp[uvp++]) - 128;
149 | u = (0xff & yuv420sp[uvp++]) - 128;
150 | }
151 | int y1192 = 1192 * y;
152 | int r = (y1192 + 1634 * v);
153 | int g = (y1192 - 833 * v - 400 * u);
154 | int b = (y1192 + 2066 * u);
155 |
156 | if (r < 0) r = 0;
157 | else if (r > 262143) r = 262143;
158 | if (g < 0) g = 0;
159 | else if (g > 262143) g = 262143;
160 | if (b < 0) b = 0;
161 | else if (b > 262143) b = 262143;
162 |
163 | rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
164 | }
165 | }
166 | return rgb;
167 | }
168 |
169 | /**
170 | * Convert an RGB image into a Bitmap.
171 | *
172 | * @param rgb
173 | * Integer array representing an RGB image.
174 | * @param width
175 | * Width of the image.
176 | * @param height
177 | * Height of the image.
178 | * @return Bitmap of the RGB image.
179 | * @throws NullPointerException
180 | * if RGB integer array is NULL.
181 | */
182 | public static Bitmap rgbToBitmap(int[] rgb, int width, int height) {
183 | if (rgb == null) throw new NullPointerException();
184 |
185 | Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
186 | bitmap.setPixels(rgb, 0, width, 0, 0, width, height);
187 | return bitmap;
188 | }
189 |
190 | /**
191 | * Convert an Luma image into Greyscale.
192 | *
193 | * @param lum
194 | * Integer array representing an Luma image.
195 | * @param width
196 | * Width of the image.
197 | * @param height
198 | * Height of the image.
199 | * @return Bitmap of the Luma image.
200 | * @throws NullPointerException
201 | * if RGB integer array is NULL.
202 | */
203 | public static Bitmap lumaToGreyscale(int[] lum, int width, int height) {
204 | if (lum == null) throw new NullPointerException();
205 |
206 | Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
207 | for (int y = 0, xy = 0; y < bitmap.getHeight(); y++) {
208 | for (int x = 0; x < bitmap.getWidth(); x++, xy++) {
209 | int luma = lum[xy];
210 | bitmap.setPixel(x, y, Color.argb(1, luma, luma, luma));
211 | }
212 | }
213 | return bitmap;
214 | }
215 |
216 | /**
217 | * Rotate the given Bitmap by the given degrees.
218 | *
219 | * @param bmp
220 | * Bitmap to rotate.
221 | * @param degrees
222 | * Degrees to rotate.
223 | * @return Bitmap which was rotated.
224 | */
225 | public static Bitmap rotate(Bitmap bmp, int degrees) {
226 | if (bmp == null) throw new NullPointerException();
227 |
228 | // getting scales of the image
229 | int width = bmp.getWidth();
230 | int height = bmp.getHeight();
231 |
232 | // Creating a Matrix and rotating it to 90 degrees
233 | Matrix matrix = new Matrix();
234 | matrix.postRotate(degrees);
235 |
236 | // Getting the rotated Bitmap
237 | Bitmap rotatedBmp = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix, true);
238 | ByteArrayOutputStream stream = new ByteArrayOutputStream();
239 | rotatedBmp.compress(Bitmap.CompressFormat.JPEG, 100, stream);
240 | return rotatedBmp;
241 | }
242 |
243 | /**
244 | * Rotate the given image in byte array format by the given degrees.
245 | *
246 | * @param data
247 | * Bitmap to rotate in byte array form.
248 | * @param degrees
249 | * Degrees to rotate.
250 | * @return Byte array format of an image which was rotated.
251 | */
252 | public static byte[] rotate(byte[] data, int degrees) {
253 | if (data == null) throw new NullPointerException();
254 |
255 | // Convert the byte data into a Bitmap
256 | Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
257 |
258 | // Getting the rotated Bitmap
259 | Bitmap rotatedBmp = rotate(bmp, degrees);
260 |
261 | // Get the byte array from the Bitmap
262 | ByteArrayOutputStream stream = new ByteArrayOutputStream();
263 | rotatedBmp.compress(Bitmap.CompressFormat.JPEG, 100, stream);
264 | return stream.toByteArray();
265 | }
266 | }
267 |
--------------------------------------------------------------------------------