├── Part [4] Edge Detecion & Buttons
├── AndroidManifest.xml
├── MainActivity.java
└── activity_main.xml
├── README.md
├── [Part 7] Deep Learning Face Detection
├── AndroidManifest.xml
├── MainActivity.java
└── activity_main.xml
├── [part 2]Install (and Compile) OpenCV with Android Studio
└── AndroidManifest.xml
├── [part 3] Launch Camera & Process frames
├── AndroidManifest.xml
├── MainActivity.java
└── activity_main.xml
└── [part 5-6] DNN Module and Tiny YOLO
├── AndroidManifest.xml
├── MainActivity.java
└── activity_main.xml
/Part [4] Edge Detecion & Buttons/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Part [4] Edge Detecion & Buttons/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.androidseries;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.SurfaceView;
6 | import android.view.View;
7 | import android.widget.Toast;
8 |
9 | import org.opencv.android.BaseLoaderCallback;
10 | import org.opencv.android.CameraBridgeViewBase;
11 | import org.opencv.android.JavaCameraView;
12 | import org.opencv.android.OpenCVLoader;
13 | import org.opencv.core.Core;
14 | import org.opencv.core.Mat;
15 | import org.opencv.*;
16 | import org.opencv.core.Point;
17 | import org.opencv.core.Size;
18 | import org.opencv.imgproc.Imgproc;
19 |
20 |
21 | import java.util.Random;
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2 {
30 |
31 | CameraBridgeViewBase cameraBridgeViewBase;
32 | BaseLoaderCallback baseLoaderCallback;
33 | boolean startCanny = false;
34 |
35 |
36 |
37 |
38 |
39 | public void Canny(View Button){
40 |
41 | if (startCanny == false){
42 | startCanny = true;
43 | }
44 |
45 | else{
46 |
47 | startCanny = false;
48 |
49 |
50 | }
51 |
52 |
53 |
54 |
55 | }
56 |
57 |
58 |
59 |
60 |
61 |
62 | @Override
63 | protected void onCreate(Bundle savedInstanceState) {
64 | super.onCreate(savedInstanceState);
65 | setContentView(R.layout.activity_main);
66 |
67 |
68 | cameraBridgeViewBase = (JavaCameraView)findViewById(R.id.CameraView);
69 | cameraBridgeViewBase.setVisibility(SurfaceView.VISIBLE);
70 | cameraBridgeViewBase.setCvCameraViewListener(this);
71 |
72 |
73 | //System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
74 | baseLoaderCallback = new BaseLoaderCallback(this) {
75 | @Override
76 | public void onManagerConnected(int status) {
77 | super.onManagerConnected(status);
78 |
79 | switch(status){
80 |
81 | case BaseLoaderCallback.SUCCESS:
82 | cameraBridgeViewBase.enableView();
83 | break;
84 | default:
85 | super.onManagerConnected(status);
86 | break;
87 | }
88 |
89 |
90 | }
91 |
92 | };
93 |
94 |
95 |
96 |
97 | }
98 |
99 | @Override
100 | public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
101 |
102 | Mat frame = inputFrame.rgba();
103 |
104 | if (startCanny == true) {
105 |
106 | Imgproc.cvtColor(frame, frame, Imgproc.COLOR_RGBA2GRAY);
107 | Imgproc.Canny(frame, frame, 100, 80);
108 |
109 | }
110 |
111 |
112 |
113 | return frame;
114 | }
115 |
116 |
117 | @Override
118 | public void onCameraViewStarted(int width, int height) {
119 |
120 | }
121 |
122 |
123 | @Override
124 | public void onCameraViewStopped() {
125 |
126 | }
127 |
128 |
129 | @Override
130 | protected void onResume() {
131 | super.onResume();
132 |
133 | if (!OpenCVLoader.initDebug()){
134 | Toast.makeText(getApplicationContext(),"There's a problem, yo!", Toast.LENGTH_SHORT).show();
135 | }
136 |
137 | else
138 | {
139 | baseLoaderCallback.onManagerConnected(baseLoaderCallback.SUCCESS);
140 | }
141 |
142 |
143 |
144 | }
145 |
146 | @Override
147 | protected void onPause() {
148 | super.onPause();
149 | if(cameraBridgeViewBase!=null){
150 |
151 | cameraBridgeViewBase.disableView();
152 | }
153 |
154 | }
155 |
156 |
157 | @Override
158 | protected void onDestroy() {
159 | super.onDestroy();
160 | if (cameraBridgeViewBase!=null){
161 | cameraBridgeViewBase.disableView();
162 | }
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/Part [4] Edge Detecion & Buttons/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
18 |
19 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android Deep Learning with OpenCV
2 |
3 | Hey what is up, everybody! Here I'll be posting all the code from my new Android series! Hope you enjoy and find it useful!
4 |
5 | ## Part 1 - Let's build an Android AI App with OpenCV
6 | https://youtu.be/lGtUA5wz0tk
7 | 
8 |
9 |
10 | ## Part 2 - Compile Android Studio with OpenCV
11 | https://youtu.be/7J4b0Djcips
12 | 
13 |
14 |
15 | ## Part 3 - Launch OpenCV camera view and actually build our first app that processes frames!
16 | https://youtu.be/20q-rZzNROY
17 | 
18 |
19 |
20 | ## Part 4 - OpenCV Edge Detection in Android Studio & Creating Buttons
21 | https://youtu.be/5nQCyacyM4w
22 | 
23 |
24 |
25 | ## Part 5 - Run TensorFlow, PyTorch, Darknet, Caffe Neural Nets on Android With OpenCV
26 | https://youtu.be/-e76BQfUNFc
27 | 
28 |
29 | ## Part 6 - Run YOLOv3 on Android with OpenCV (Custom Trained YOLO too)
30 | https://youtu.be/JasVghcUeyg
31 | 
32 |
33 | ## Part 7 - Deep Learning Face Detection on Android with OpenCV
34 | https://youtu.be/pMZsttT57Zo
35 | 
36 |
37 | ## BusNumberApp: AI App that Reads Bus Numbers Explained (And Open-Sourced!)
38 | In this video I explain the project which inspired this series of videos about deep learning development on Android.
39 | https://youtu.be/ohsCVVF1dC0
40 | 
41 |
42 |
43 |
--------------------------------------------------------------------------------
/[Part 7] Deep Learning Face Detection/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
24 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/[Part 7] Deep Learning Face Detection/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.androidseries;
2 |
3 | import android.os.Environment;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.os.Bundle;
6 | import android.util.Log;
7 | import android.view.SurfaceView;
8 | import android.view.View;
9 | import android.widget.Toast;
10 |
11 | import org.opencv.android.BaseLoaderCallback;
12 | import org.opencv.android.CameraBridgeViewBase;
13 | import org.opencv.android.JavaCameraView;
14 | import org.opencv.android.OpenCVLoader;
15 | import org.opencv.core.Core;
16 | import org.opencv.core.CvType;
17 | import org.opencv.core.Mat;
18 | import org.opencv.*;
19 | import org.opencv.core.MatOfFloat;
20 | import org.opencv.core.MatOfInt;
21 | import org.opencv.core.MatOfRect;
22 | import org.opencv.core.Point;
23 | import org.opencv.core.Rect;
24 | import org.opencv.core.Scalar;
25 | import org.opencv.core.Size;
26 | import org.opencv.dnn.Net;
27 | import org.opencv.imgproc.Imgproc;
28 |
29 | import org.opencv.dnn.Dnn;
30 | import org.opencv.utils.Converters;
31 |
32 |
33 | import java.util.ArrayList;
34 | import java.util.Arrays;
35 | import java.util.List;
36 | import java.util.Random;
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2 {
45 |
46 | CameraBridgeViewBase cameraBridgeViewBase;
47 | BaseLoaderCallback baseLoaderCallback;
48 | boolean startYolo = false;
49 | boolean firstTimeYolo = false;
50 |
51 | boolean startFaces = false;
52 | boolean firstTimeFaces = false;
53 |
54 |
55 |
56 | Net tinyYolo;
57 | Net detector;
58 |
59 |
60 | public void YOLO(View Button){
61 |
62 | if (startYolo == false){
63 |
64 |
65 |
66 |
67 | startYolo = true;
68 |
69 | if (firstTimeYolo == false){
70 |
71 |
72 | firstTimeYolo = true;
73 | String tinyYoloCfg = Environment.getExternalStorageDirectory() + "/dnns/yolov3-tiny.cfg" ;
74 | String tinyYoloWeights = Environment.getExternalStorageDirectory() + "/dnns/yolov3-tiny.weights";
75 |
76 | tinyYolo = Dnn.readNetFromDarknet(tinyYoloCfg, tinyYoloWeights);
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | }
87 |
88 |
89 |
90 | }
91 |
92 | else{
93 |
94 | startYolo = false;
95 |
96 |
97 | }
98 |
99 |
100 |
101 |
102 | }
103 |
104 |
105 |
106 |
107 | public void Faces(View Button){
108 |
109 | if (startFaces == false){
110 |
111 |
112 |
113 |
114 | startFaces = true;
115 |
116 | if (firstTimeFaces == false){
117 |
118 |
119 | firstTimeFaces = true;
120 | String protoPath = Environment.getExternalStorageDirectory() + "/dnns/deploy.prototxt" ;
121 | String caffeWeights = Environment.getExternalStorageDirectory() + "/dnns/res10_300x300_ssd_iter_140000.caffemodel";
122 |
123 | detector = Dnn.readNetFromCaffe(protoPath, caffeWeights);
124 |
125 |
126 | }
127 |
128 |
129 |
130 | }
131 |
132 | else{
133 |
134 | startFaces = false;
135 |
136 |
137 | }
138 |
139 |
140 |
141 |
142 | }
143 |
144 |
145 |
146 |
147 | @Override
148 | protected void onCreate(Bundle savedInstanceState) {
149 | super.onCreate(savedInstanceState);
150 | setContentView(R.layout.activity_main);
151 |
152 |
153 | cameraBridgeViewBase = (JavaCameraView)findViewById(R.id.CameraView);
154 | cameraBridgeViewBase.setVisibility(SurfaceView.VISIBLE);
155 | cameraBridgeViewBase.setCvCameraViewListener(this);
156 |
157 |
158 | //System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
159 | baseLoaderCallback = new BaseLoaderCallback(this) {
160 | @Override
161 | public void onManagerConnected(int status) {
162 | super.onManagerConnected(status);
163 |
164 | switch(status){
165 |
166 | case BaseLoaderCallback.SUCCESS:
167 | cameraBridgeViewBase.enableView();
168 | break;
169 | default:
170 | super.onManagerConnected(status);
171 | break;
172 | }
173 |
174 |
175 | }
176 |
177 | };
178 |
179 |
180 |
181 |
182 | }
183 |
184 | @Override
185 | public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
186 |
187 | Mat frame = inputFrame.rgba();
188 |
189 | if (startYolo == true) {
190 |
191 | Imgproc.cvtColor(frame, frame, Imgproc.COLOR_RGBA2RGB);
192 |
193 |
194 |
195 | Mat imageBlob = Dnn.blobFromImage(frame, 0.00392, new Size(416,416),new Scalar(0, 0, 0),/*swapRB*/false, /*crop*/false);
196 |
197 |
198 | tinyYolo.setInput(imageBlob);
199 |
200 |
201 |
202 | java.util.List result = new java.util.ArrayList(2);
203 |
204 | List outBlobNames = new java.util.ArrayList<>();
205 | outBlobNames.add(0, "yolo_16");
206 | outBlobNames.add(1, "yolo_23");
207 |
208 | tinyYolo.forward(result,outBlobNames);
209 |
210 |
211 | float confThreshold = 0.3f;
212 |
213 |
214 |
215 | List clsIds = new ArrayList<>();
216 | List confs = new ArrayList<>();
217 | List rects = new ArrayList<>();
218 |
219 |
220 |
221 |
222 | for (int i = 0; i < result.size(); ++i)
223 | {
224 |
225 | Mat level = result.get(i);
226 |
227 | for (int j = 0; j < level.rows(); ++j)
228 | {
229 | Mat row = level.row(j);
230 | Mat scores = row.colRange(5, level.cols());
231 |
232 | Core.MinMaxLocResult mm = Core.minMaxLoc(scores);
233 |
234 |
235 |
236 |
237 | float confidence = (float)mm.maxVal;
238 |
239 |
240 | Point classIdPoint = mm.maxLoc;
241 |
242 |
243 |
244 | if (confidence > confThreshold)
245 | {
246 | int centerX = (int)(row.get(0,0)[0] * frame.cols());
247 | int centerY = (int)(row.get(0,1)[0] * frame.rows());
248 | int width = (int)(row.get(0,2)[0] * frame.cols());
249 | int height = (int)(row.get(0,3)[0] * frame.rows());
250 |
251 |
252 | int left = centerX - width / 2;
253 | int top = centerY - height / 2;
254 |
255 | clsIds.add((int)classIdPoint.x);
256 | confs.add((float)confidence);
257 |
258 |
259 |
260 |
261 | rects.add(new Rect(left, top, width, height));
262 | }
263 | }
264 | }
265 | int ArrayLength = confs.size();
266 |
267 | if (ArrayLength>=1) {
268 | // Apply non-maximum suppression procedure.
269 | float nmsThresh = 0.2f;
270 |
271 |
272 |
273 |
274 | MatOfFloat confidences = new MatOfFloat(Converters.vector_float_to_Mat(confs));
275 |
276 |
277 | Rect[] boxesArray = rects.toArray(new Rect[0]);
278 |
279 | MatOfRect boxes = new MatOfRect(boxesArray);
280 |
281 | MatOfInt indices = new MatOfInt();
282 |
283 |
284 |
285 | Dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThresh, indices);
286 |
287 |
288 | // Draw result boxes:
289 | int[] ind = indices.toArray();
290 | for (int i = 0; i < ind.length; ++i) {
291 |
292 | int idx = ind[i];
293 | Rect box = boxesArray[idx];
294 |
295 | int idGuy = clsIds.get(idx);
296 |
297 | float conf = confs.get(idx);
298 |
299 |
300 | List cocoNames = Arrays.asList("a person", "a bicycle", "a motorbike", "an airplane", "a bus", "a train", "a truck", "a boat", "a traffic light", "a fire hydrant", "a stop sign", "a parking meter", "a car", "a bench", "a bird", "a cat", "a dog", "a horse", "a sheep", "a cow", "an elephant", "a bear", "a zebra", "a giraffe", "a backpack", "an umbrella", "a handbag", "a tie", "a suitcase", "a frisbee", "skis", "a snowboard", "a sports ball", "a kite", "a baseball bat", "a baseball glove", "a skateboard", "a surfboard", "a tennis racket", "a bottle", "a wine glass", "a cup", "a fork", "a knife", "a spoon", "a bowl", "a banana", "an apple", "a sandwich", "an orange", "broccoli", "a carrot", "a hot dog", "a pizza", "a doughnut", "a cake", "a chair", "a sofa", "a potted plant", "a bed", "a dining table", "a toilet", "a TV monitor", "a laptop", "a computer mouse", "a remote control", "a keyboard", "a cell phone", "a microwave", "an oven", "a toaster", "a sink", "a refrigerator", "a book", "a clock", "a vase", "a pair of scissors", "a teddy bear", "a hair drier", "a toothbrush");
301 |
302 |
303 |
304 | int intConf = (int) (conf * 100);
305 |
306 |
307 |
308 | Imgproc.putText(frame,cocoNames.get(idGuy) + " " + intConf + "%",box.tl(),Core.FONT_HERSHEY_SIMPLEX, 2, new Scalar(255,255,0),2);
309 |
310 |
311 |
312 | Imgproc.rectangle(frame, box.tl(), box.br(), new Scalar(255, 0, 0), 2);
313 |
314 |
315 |
316 |
317 |
318 | }
319 | }
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 | }
330 |
331 |
332 | if (startFaces == true){
333 |
334 | Imgproc.cvtColor(frame, frame, Imgproc.COLOR_RGBA2RGB);
335 |
336 |
337 |
338 |
339 | Mat imageBlob = Dnn.blobFromImage(frame, 1.0, new Size(300, 300), new Scalar(104.0, 177.0, 123.0), true, false, CvType.CV_32F);
340 |
341 | detector.setInput(imageBlob); //set the input to network model
342 | Mat detections = detector.forward(); //feed forward the input to the netwrok to get the output
343 |
344 | int cols = frame.cols();
345 | int rows = frame.rows();
346 |
347 | double THRESHOLD = 0.55;
348 |
349 |
350 | detections = detections.reshape(1, (int)detections.total() / 7);
351 |
352 | Log.d("EXPERIMENT5:ROWS", detections.rows()+"");
353 |
354 | for (int i = 0; i < detections.rows(); ++i) {
355 |
356 |
357 |
358 | double confidence = detections.get(i, 2)[0];
359 |
360 |
361 | Log.d("EXPERIMENT6", i+" "+confidence+" "+THRESHOLD);
362 | if (confidence > THRESHOLD) {
363 |
364 | int left = (int)(detections.get(i, 3)[0] * cols);
365 | int top = (int)(detections.get(i, 4)[0] * rows);
366 | int right = (int)(detections.get(i, 5)[0] * cols);
367 | int bottom = (int)(detections.get(i, 6)[0] * rows);
368 |
369 |
370 | // Draw rectangle around detected object
371 |
372 | if (left<0){
373 | left=0;
374 | }
375 | if (top<0){
376 | top=0;
377 | }
378 | if (right<0){
379 | right=0;
380 | }
381 | if (bottom<0){
382 | bottom=0;
383 | }
384 |
385 | int xLim=frame.size(1);
386 | int yLim=frame.size(0);
387 |
388 | if (left>=xLim){
389 | left=xLim-2;
390 | }
391 | if (right>=xLim){
392 | right=xLim-2;
393 | }
394 |
395 | if (top>=yLim){
396 | top=yLim-2;
397 | }
398 | if (bottom>=yLim){
399 | bottom=yLim-2;
400 | }
401 |
402 |
403 | Imgproc.rectangle(frame, new Point(left, top), new Point(right, bottom),new Scalar(255, 255, 0),2);
404 |
405 |
406 |
407 |
408 |
409 |
410 | } } }
411 |
412 |
413 |
414 |
415 |
416 |
417 | return frame;
418 | }
419 |
420 |
421 | @Override
422 | public void onCameraViewStarted(int width, int height) {
423 |
424 |
425 | if (startYolo == true){
426 |
427 | String tinyYoloCfg = Environment.getExternalStorageDirectory() + "/dnns/yolov3-tiny.cfg" ;
428 | String tinyYoloWeights = Environment.getExternalStorageDirectory() + "/dnns/yolov3-tiny.weights";
429 |
430 | tinyYolo = Dnn.readNetFromDarknet(tinyYoloCfg, tinyYoloWeights);
431 |
432 |
433 | }
434 |
435 |
436 | if (startFaces == true){
437 |
438 | String protoPath = Environment.getExternalStorageDirectory() + "/dnns/deploy.prototxt" ;
439 | String caffeWeights = Environment.getExternalStorageDirectory() + "/dnns/res10_300x300_ssd_iter_140000.caffemodel";
440 |
441 | detector = Dnn.readNetFromDarknet(protoPath, caffeWeights);
442 |
443 |
444 | }
445 |
446 |
447 |
448 | }
449 |
450 |
451 | @Override
452 | public void onCameraViewStopped() {
453 |
454 | }
455 |
456 |
457 | @Override
458 | protected void onResume() {
459 | super.onResume();
460 |
461 | if (!OpenCVLoader.initDebug()){
462 | Toast.makeText(getApplicationContext(),"There's a problem, yo!", Toast.LENGTH_SHORT).show();
463 | }
464 |
465 | else
466 | {
467 | baseLoaderCallback.onManagerConnected(baseLoaderCallback.SUCCESS);
468 | }
469 |
470 |
471 |
472 | }
473 |
474 | @Override
475 | protected void onPause() {
476 | super.onPause();
477 | if(cameraBridgeViewBase!=null){
478 |
479 | cameraBridgeViewBase.disableView();
480 | }
481 |
482 | }
483 |
484 |
485 | @Override
486 | protected void onDestroy() {
487 | super.onDestroy();
488 | if (cameraBridgeViewBase!=null){
489 | cameraBridgeViewBase.disableView();
490 | }
491 | }
492 | }
493 |
--------------------------------------------------------------------------------
/[Part 7] Deep Learning Face Detection/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
18 |
19 |
30 |
31 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/[part 2]Install (and Compile) OpenCV with Android Studio/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/[part 3] Launch Camera & Process frames/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/[part 3] Launch Camera & Process frames/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.androidseries;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.SurfaceView;
6 | import android.widget.Toast;
7 |
8 | import org.opencv.android.BaseLoaderCallback;
9 | import org.opencv.android.CameraBridgeViewBase;
10 | import org.opencv.android.JavaCameraView;
11 | import org.opencv.android.OpenCVLoader;
12 | import org.opencv.core.Core;
13 | import org.opencv.core.Mat;
14 | import org.opencv.*;
15 | import org.opencv.imgproc.Imgproc;
16 |
17 |
18 | import java.util.Random;
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2 {
27 |
28 | CameraBridgeViewBase cameraBridgeViewBase;
29 | BaseLoaderCallback baseLoaderCallback;
30 | int counter = 0;
31 |
32 |
33 | @Override
34 | protected void onCreate(Bundle savedInstanceState) {
35 | super.onCreate(savedInstanceState);
36 | setContentView(R.layout.activity_main);
37 |
38 |
39 | cameraBridgeViewBase = (JavaCameraView)findViewById(R.id.CameraView);
40 | cameraBridgeViewBase.setVisibility(SurfaceView.VISIBLE);
41 | cameraBridgeViewBase.setCvCameraViewListener(this);
42 |
43 |
44 | //System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
45 | baseLoaderCallback = new BaseLoaderCallback(this) {
46 | @Override
47 | public void onManagerConnected(int status) {
48 | super.onManagerConnected(status);
49 |
50 | switch(status){
51 |
52 | case BaseLoaderCallback.SUCCESS:
53 | cameraBridgeViewBase.enableView();
54 | break;
55 | default:
56 | super.onManagerConnected(status);
57 | break;
58 | }
59 |
60 |
61 | }
62 |
63 | };
64 |
65 |
66 |
67 |
68 | }
69 |
70 | @Override
71 | public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
72 |
73 | Mat frame = inputFrame.rgba();
74 |
75 | if (counter % 2 == 0){
76 |
77 | Core.flip(frame, frame, 1);
78 | Imgproc.cvtColor(frame, frame, Imgproc.COLOR_RGBA2GRAY);
79 |
80 |
81 | }
82 |
83 | counter = counter + 1;
84 |
85 |
86 |
87 |
88 |
89 |
90 | return frame;
91 | }
92 |
93 |
94 | @Override
95 | public void onCameraViewStarted(int width, int height) {
96 |
97 | }
98 |
99 |
100 | @Override
101 | public void onCameraViewStopped() {
102 |
103 | }
104 |
105 |
106 | @Override
107 | protected void onResume() {
108 | super.onResume();
109 |
110 | if (!OpenCVLoader.initDebug()){
111 | Toast.makeText(getApplicationContext(),"There's a problem, yo!", Toast.LENGTH_SHORT).show();
112 | }
113 |
114 | else
115 | {
116 | baseLoaderCallback.onManagerConnected(baseLoaderCallback.SUCCESS);
117 | }
118 |
119 |
120 |
121 | }
122 |
123 | @Override
124 | protected void onPause() {
125 | super.onPause();
126 | if(cameraBridgeViewBase!=null){
127 |
128 | cameraBridgeViewBase.disableView();
129 | }
130 |
131 | }
132 |
133 |
134 | @Override
135 | protected void onDestroy() {
136 | super.onDestroy();
137 | if (cameraBridgeViewBase!=null){
138 | cameraBridgeViewBase.disableView();
139 | }
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/[part 3] Launch Camera & Process frames/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
--------------------------------------------------------------------------------
/[part 5-6] DNN Module and Tiny YOLO/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
24 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/[part 5-6] DNN Module and Tiny YOLO/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.androidseries;
2 |
3 | import android.os.Environment;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.os.Bundle;
6 | import android.view.SurfaceView;
7 | import android.view.View;
8 | import android.widget.Toast;
9 |
10 | import org.opencv.android.BaseLoaderCallback;
11 | import org.opencv.android.CameraBridgeViewBase;
12 | import org.opencv.android.JavaCameraView;
13 | import org.opencv.android.OpenCVLoader;
14 | import org.opencv.core.Core;
15 | import org.opencv.core.Mat;
16 | import org.opencv.*;
17 | import org.opencv.core.MatOfFloat;
18 | import org.opencv.core.MatOfInt;
19 | import org.opencv.core.MatOfRect;
20 | import org.opencv.core.Point;
21 | import org.opencv.core.Rect;
22 | import org.opencv.core.Scalar;
23 | import org.opencv.core.Size;
24 | import org.opencv.dnn.Net;
25 | import org.opencv.imgproc.Imgproc;
26 |
27 | import org.opencv.dnn.Dnn;
28 | import org.opencv.utils.Converters;
29 |
30 |
31 | import java.util.ArrayList;
32 | import java.util.Arrays;
33 | import java.util.List;
34 | import java.util.Random;
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2 {
43 |
44 | CameraBridgeViewBase cameraBridgeViewBase;
45 | BaseLoaderCallback baseLoaderCallback;
46 | boolean startYolo = false;
47 | boolean firstTimeYolo = false;
48 | Net tinyYolo;
49 |
50 |
51 |
52 | public void YOLO(View Button){
53 |
54 | if (startYolo == false){
55 |
56 |
57 |
58 |
59 | startYolo = true;
60 |
61 | if (firstTimeYolo == false){
62 |
63 |
64 | firstTimeYolo = true;
65 | String tinyYoloCfg = Environment.getExternalStorageDirectory() + "/dnns/yolov3-tiny.cfg" ;
66 | String tinyYoloWeights = Environment.getExternalStorageDirectory() + "/dnns/yolov3-tiny.weights";
67 |
68 | tinyYolo = Dnn.readNetFromDarknet(tinyYoloCfg, tinyYoloWeights);
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | }
79 |
80 |
81 |
82 | }
83 |
84 | else{
85 |
86 | startYolo = false;
87 |
88 |
89 | }
90 |
91 |
92 |
93 |
94 | }
95 |
96 |
97 |
98 |
99 |
100 |
101 | @Override
102 | protected void onCreate(Bundle savedInstanceState) {
103 | super.onCreate(savedInstanceState);
104 | setContentView(R.layout.activity_main);
105 |
106 |
107 | cameraBridgeViewBase = (JavaCameraView)findViewById(R.id.CameraView);
108 | cameraBridgeViewBase.setVisibility(SurfaceView.VISIBLE);
109 | cameraBridgeViewBase.setCvCameraViewListener(this);
110 |
111 |
112 | //System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
113 | baseLoaderCallback = new BaseLoaderCallback(this) {
114 | @Override
115 | public void onManagerConnected(int status) {
116 | super.onManagerConnected(status);
117 |
118 | switch(status){
119 |
120 | case BaseLoaderCallback.SUCCESS:
121 | cameraBridgeViewBase.enableView();
122 | break;
123 | default:
124 | super.onManagerConnected(status);
125 | break;
126 | }
127 |
128 |
129 | }
130 |
131 | };
132 |
133 |
134 |
135 |
136 | }
137 |
138 | @Override
139 | public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
140 |
141 | Mat frame = inputFrame.rgba();
142 |
143 | if (startYolo == true) {
144 |
145 | Imgproc.cvtColor(frame, frame, Imgproc.COLOR_RGBA2RGB);
146 |
147 |
148 |
149 | Mat imageBlob = Dnn.blobFromImage(frame, 0.00392, new Size(416,416),new Scalar(0, 0, 0),/*swapRB*/false, /*crop*/false);
150 |
151 |
152 | tinyYolo.setInput(imageBlob);
153 |
154 |
155 |
156 | java.util.List result = new java.util.ArrayList(2);
157 |
158 | List outBlobNames = new java.util.ArrayList<>();
159 | outBlobNames.add(0, "yolo_16");
160 | outBlobNames.add(1, "yolo_23");
161 |
162 | tinyYolo.forward(result,outBlobNames);
163 |
164 |
165 | float confThreshold = 0.3f;
166 |
167 |
168 |
169 | List clsIds = new ArrayList<>();
170 | List confs = new ArrayList<>();
171 | List rects = new ArrayList<>();
172 |
173 |
174 |
175 |
176 | for (int i = 0; i < result.size(); ++i)
177 | {
178 |
179 | Mat level = result.get(i);
180 |
181 | for (int j = 0; j < level.rows(); ++j)
182 | {
183 | Mat row = level.row(j);
184 | Mat scores = row.colRange(5, level.cols());
185 |
186 | Core.MinMaxLocResult mm = Core.minMaxLoc(scores);
187 |
188 |
189 |
190 |
191 | float confidence = (float)mm.maxVal;
192 |
193 |
194 | Point classIdPoint = mm.maxLoc;
195 |
196 |
197 |
198 | if (confidence > confThreshold)
199 | {
200 | int centerX = (int)(row.get(0,0)[0] * frame.cols());
201 | int centerY = (int)(row.get(0,1)[0] * frame.rows());
202 | int width = (int)(row.get(0,2)[0] * frame.cols());
203 | int height = (int)(row.get(0,3)[0] * frame.rows());
204 |
205 |
206 | int left = centerX - width / 2;
207 | int top = centerY - height / 2;
208 |
209 | clsIds.add((int)classIdPoint.x);
210 | confs.add((float)confidence);
211 |
212 |
213 |
214 |
215 | rects.add(new Rect(left, top, width, height));
216 | }
217 | }
218 | }
219 | int ArrayLength = confs.size();
220 |
221 | if (ArrayLength>=1) {
222 | // Apply non-maximum suppression procedure.
223 | float nmsThresh = 0.2f;
224 |
225 |
226 |
227 |
228 | MatOfFloat confidences = new MatOfFloat(Converters.vector_float_to_Mat(confs));
229 |
230 |
231 | Rect[] boxesArray = rects.toArray(new Rect[0]);
232 |
233 | MatOfRect boxes = new MatOfRect(boxesArray);
234 |
235 | MatOfInt indices = new MatOfInt();
236 |
237 |
238 |
239 | Dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThresh, indices);
240 |
241 |
242 | // Draw result boxes:
243 | int[] ind = indices.toArray();
244 | for (int i = 0; i < ind.length; ++i) {
245 |
246 | int idx = ind[i];
247 | Rect box = boxesArray[idx];
248 |
249 | int idGuy = clsIds.get(idx);
250 |
251 | float conf = confs.get(idx);
252 |
253 |
254 | List cocoNames = Arrays.asList("a person", "a bicycle", "a motorbike", "an airplane", "a bus", "a train", "a truck", "a boat", "a traffic light", "a fire hydrant", "a stop sign", "a parking meter", "a car", "a bench", "a bird", "a cat", "a dog", "a horse", "a sheep", "a cow", "an elephant", "a bear", "a zebra", "a giraffe", "a backpack", "an umbrella", "a handbag", "a tie", "a suitcase", "a frisbee", "skis", "a snowboard", "a sports ball", "a kite", "a baseball bat", "a baseball glove", "a skateboard", "a surfboard", "a tennis racket", "a bottle", "a wine glass", "a cup", "a fork", "a knife", "a spoon", "a bowl", "a banana", "an apple", "a sandwich", "an orange", "broccoli", "a carrot", "a hot dog", "a pizza", "a doughnut", "a cake", "a chair", "a sofa", "a potted plant", "a bed", "a dining table", "a toilet", "a TV monitor", "a laptop", "a computer mouse", "a remote control", "a keyboard", "a cell phone", "a microwave", "an oven", "a toaster", "a sink", "a refrigerator", "a book", "a clock", "a vase", "a pair of scissors", "a teddy bear", "a hair drier", "a toothbrush");
255 |
256 |
257 |
258 | int intConf = (int) (conf * 100);
259 |
260 |
261 |
262 | Imgproc.putText(frame,cocoNames.get(idGuy) + " " + intConf + "%",box.tl(),Core.FONT_HERSHEY_SIMPLEX, 2, new Scalar(255,255,0),2);
263 |
264 |
265 |
266 | Imgproc.rectangle(frame, box.tl(), box.br(), new Scalar(255, 0, 0), 2);
267 |
268 |
269 |
270 |
271 |
272 | }
273 | }
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 | }
284 |
285 |
286 |
287 | return frame;
288 | }
289 |
290 |
291 | @Override
292 | public void onCameraViewStarted(int width, int height) {
293 |
294 |
295 | if (startYolo == true){
296 |
297 | String tinyYoloCfg = Environment.getExternalStorageDirectory() + "/dnns/yolov3-tiny.cfg" ;
298 | String tinyYoloWeights = Environment.getExternalStorageDirectory() + "/dnns/yolov3-tiny.weights";
299 |
300 | tinyYolo = Dnn.readNetFromDarknet(tinyYoloCfg, tinyYoloWeights);
301 |
302 |
303 | }
304 |
305 |
306 |
307 | }
308 |
309 |
310 | @Override
311 | public void onCameraViewStopped() {
312 |
313 | }
314 |
315 |
316 | @Override
317 | protected void onResume() {
318 | super.onResume();
319 |
320 | if (!OpenCVLoader.initDebug()){
321 | Toast.makeText(getApplicationContext(),"There's a problem, yo!", Toast.LENGTH_SHORT).show();
322 | }
323 |
324 | else
325 | {
326 | baseLoaderCallback.onManagerConnected(baseLoaderCallback.SUCCESS);
327 | }
328 |
329 |
330 |
331 | }
332 |
333 | @Override
334 | protected void onPause() {
335 | super.onPause();
336 | if(cameraBridgeViewBase!=null){
337 |
338 | cameraBridgeViewBase.disableView();
339 | }
340 |
341 | }
342 |
343 |
344 | @Override
345 | protected void onDestroy() {
346 | super.onDestroy();
347 | if (cameraBridgeViewBase!=null){
348 | cameraBridgeViewBase.disableView();
349 | }
350 | }
351 | }
352 |
--------------------------------------------------------------------------------
/[part 5-6] DNN Module and Tiny YOLO/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
18 |
19 |
34 |
35 |
36 |
--------------------------------------------------------------------------------