Bonsoir,

J'ai trouvé un code sur Github, un projet android de réalité augmentée qui permet d'afficher un cube sur le centre de la main (après l'avoir détectée) avec OpenGL.

Je souhaite utiliser certaines fonctionnalitées plus ou moins présentes dans ce code; j'ai donc tenté de le comprendre en commentant les 3 classes du projet, avant, de peut être me lancer dans la création de mes propres class pour non pas afficher un cube mais dessiner certaines formes sur la main.

J'ai réussi à mettre à jour le gradle du projet et installer le SDK OpenCV, bien qu'il y est un problème au niveau de l'appel des fonctions natives (je ne fais que citer un message d'erreur), qui m'oblige à installer l'application OpenCV sur mon android avant de pouvoir utiliser l'application, bref çà compile et j'ai vu ce que çà donné.

J'ai également regardé l'API OpenCV pour tenter de comprendre et lu ce tuto de developpez.

J'ai commenté comme ce que j'ai tenté de comprendre et certains commentaires sont sans doute faux ou hors contexte.
Mais voici les 3 class en question si vous voulez jeter un oeil cela m'aiderait vraiment, mes commentaires sont en français:

MainActivity.java
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
 
/***
     * @author: Ajinkya Dhaigude
     */
 
    package com.example.ajinkya.cvisionapp;
 
    import android.content.pm.ActivityInfo;
    import android.graphics.PixelFormat;
    import android.opengl.GLSurfaceView;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.MotionEvent;
    import android.view.SurfaceView;
    import android.view.View;
    import android.view.WindowManager;
 
    import org.opencv.android.BaseLoaderCallback;
    import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
    import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
    import org.opencv.android.JavaCameraView;
    import org.opencv.android.LoaderCallbackInterface;
    import org.opencv.android.OpenCVLoader;
    import org.opencv.core.Core;
    import org.opencv.core.CvType;
    import org.opencv.core.Mat;
    import org.opencv.core.MatOfFloat;
    import org.opencv.core.MatOfInt;
    import org.opencv.core.MatOfInt4;
    import org.opencv.core.MatOfPoint;
    import org.opencv.core.Point;
    import org.opencv.core.Rect;
    import org.opencv.core.Scalar;
    import org.opencv.core.Size;
    import org.opencv.core.TermCriteria;
    import org.opencv.imgproc.Imgproc;
    import org.opencv.video.Video;
 
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
 
    public class MainActivity extends AppCompatActivity implements CvCameraViewListener2 {
 
        private JavaCameraView javaCameraView;      // Objet caméra
        private Mat ycc;                            // Objet Mat permettant de stocker une matrice par exemple, channel ou multi channel d'une image
        private int camDim[] = {320, 240};          // could be better // Dimension de la caméra
        private float offsetFactX, offsetFactY;
        private float scaleFactX, scaleFactY;       // Valeur des coordonées x et y de l'échelle
        private boolean handDetected = false;       // Etat de la détection de la main
        private Scalar handColor;                   // Couleur de la main (pour la détection)
        private Scalar minHSV;                      // Valeur des pixels min du cube (derived from Vec<_Tp, 4>, Scalar_ and Scalar can be used just as typical 4-element vectors)
        private Scalar maxHSV;                      // Valeur des pixels max du cube (derived from Vec<_Tp, 4>, Scalar_ and Scalar can be used just as typical 4-element vectors)
        private Mat frame, frame2;
        private Point palmCenter;                   //  Objet Point contenant le centre de la main
        private List<Point> fingers;                // List contenant l'ensemble des points pour reconnaitre  les doights
        private TermCriteria termCriteria;
        private List<Rect> allRoi;                  // List de Rect
        private List<Mat> allRoiHist;               // List de Mat
        private MatOfFloat ranges;
        private MatOfInt channels;
        private Mat dstBackProject;
        private MatOfPoint palmContour;
        private MatOfPoint hullPoints;
        private MatOfInt hull;
        private Mat hierarchy;
        private Mat touchedMat;
        private MatOfInt4 convexityDefects;
        private Mat nonZero;
        private Mat nonZeroRow;
        private List<MatOfPoint> contours;          // List de MAtOfPoint représentant le contour de la main
        private GLRenderer myGLRenderer;            // Objet OpenGL GLRenderer
        private int speedTime = 0;                  // Temp de rapidité
        private int speedFingers = 0;               // Temp de rapidité des doights
 
 
        // Vérifier que OpenCV charge les fonctions/méthodes natives
        static {
            if (!OpenCVLoader.initDebug())
                Log.e("init", "noo");
            else
                Log.e("init", "yess");
        }
 
        // Méthode permettant de verifier que OpenCV s'est correctement lancer et d'activer la caméra
        private BaseLoaderCallback baseLoaderCallback = new BaseLoaderCallback(this) {
            @Override
            public void onManagerConnected(int status) {
                switch (status) {
                    case LoaderCallbackInterface.SUCCESS:
                    {
                        Log.i("START!!!", "OpenCV loaded successfully");
                        javaCameraView.enableView();
                    } break;
                    default:
                    {
                        super.onManagerConnected(status);
                    } break;
                }
            }
        };
 
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // On garde la fenetre éveillé
            View decorView = getWindow().getDecorView(); // Le DecorView est la vue qui tient le fond de la fenetre
            int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN; // On met l'app en pleine écran
            decorView.setSystemUiVisibility(uiOptions); // Fonction requise pour le pleine écran (personnalisation de la vue)
            setContentView(R.layout.activity_main);
 
            javaCameraView = (JavaCameraView) findViewById(R.id.java_surface_view); // On récupère une référence vers la caméra
            javaCameraView.setVisibility(SurfaceView.VISIBLE); // On affiche ce que la caméra filme
            javaCameraView.setCvCameraViewListener(this); // On implémente un listenner sur la caméra
 
            javaCameraView.setMaxFrameSize(camDim[0], camDim[1]); // On dimensionne le cadre de la fenetre de la caméra
 
 
            GLSurfaceView myGLView = new GLSurfaceView(this);  // Une SurfaceView est utilisé& pour une surface dédié à l'affichage d'un rendu OpenGL
            myGLView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); // Configure les couleurs RGB de la surfaceView
            myGLView.getHolder().setFormat(PixelFormat.TRANSLUCENT); // Permet de rendre les pixels translucides (invisbles)
            myGLRenderer = new GLRenderer(); // Nouvel objet GLRenderer
            myGLView.setRenderer(myGLRenderer); // On applique cet objet à la surfaceView
            addContentView(myGLView, new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.WRAP_CONTENT)); // on applique le paramètre wrapContent au layout de cette surfaceview
            myGLView.setZOrderMediaOverlay(true); // Contrôler si la surface de la vue de surface est placé sur le dessus de sa fenêtre.
        }
 
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.menu_main, menu);
            return true;
        }
 
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();
 
            //noinspection SimplifiableIfStatement
            if (id == R.id.action_settings) {
                return true;
            }
 
            return super.onOptionsItemSelected(item);
        }
 
        public void onResume(){
            super.onResume();
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_10, this, baseLoaderCallback);
        }
 
        public void onDestroy() {
            super.onDestroy();
            if (javaCameraView != null)
                javaCameraView.disableView();
        }
 
        // Fonction permettant d'initialiser et de configurer les paramètres de la caméra
        @Override
        public void onCameraViewStarted(int width, int height) {
            setScaleFactors(width, height);                 // On appliquer les valeurs de largeur et hauteur de l'échelle de la fenêtre
            myGLRenderer.setVidDim(camDim[0], camDim[1]);   // On applique les dimensions à la caméra
            ycc = new Mat(height, width, CvType.CV_8UC3);   // On affecte les dimensions des channels d'une image
            handColor = new Scalar(255);                    // Représent la couleur de la main
            minHSV = new Scalar(3);                         // On affecte la valeur minimum d'un pixel
            maxHSV = new Scalar(3);                         // On affecte la valeur maximum d'un pixel
            frame = new Mat();                              // n-dimensional dense numerical single-channel or multi-channel array. | can be used to store real or complex-valued vectors and matrices, grayscale or color images, voxel volumes, vector fields, point clouds, tensors, histograms
            termCriteria = new TermCriteria(TermCriteria.COUNT | TermCriteria.EPS, 10, 1); // utilisé pour les algorythme itératif
            allRoi = new ArrayList<>();                     // Tableau de List
            allRoiHist = new ArrayList<>();                 // Tableau de List
            ranges = new MatOfFloat(0, 180);                //MatOfInt, MatOfFloat est des classes qui sont héritées de Mat et a 1 canal de type et de taille définie 1xN. Il est analogue de std :: vector <int>, std :: vector <deux>, etc dans le code C ++.
            channels = new MatOfInt(0);                     // MatOfInt, MatOfFloat est des classes qui sont héritées de Mat et a 1 canal de type et de taille définie 1xN. Il est analogue de std :: vector <int>, std :: vector <deux>, etc dans le code C ++.
            dstBackProject = new Mat();                     // n-dimensional dense numerical single-channel or multi-channel array. | can be used to store real or complex-valued vectors and matrices, grayscale or color images, voxel volumes, vector fields, point clouds, tensors, histograms
            palmContour = new MatOfPoint();                 // Tableau Vector de point correspondant au contour de la main
            hullPoints = new MatOfPoint();                  // Tableau Vector de point correspondant au point de chaque doight
            hull = new MatOfInt();                          // MatOfInt, MatOfFloat est des classes qui sont héritées de Mat et a 1 canal de type et de taille définie 1xN. Il est analogue de std :: vector <int>, std :: vector <deux>, etc dans le code C ++.
            hierarchy  = new Mat();
            touchedMat = new Mat();
            convexityDefects = new MatOfInt4();
            nonZero = new Mat();
            frame2 = new Mat();
            nonZeroRow = new Mat();
            contours = new ArrayList<>();
            palmCenter = new Point(-1, -1);                 // Point de coordonnées x et y correspondant au centre de la main
 
        }
 
        // Méthode permettant d'appliquer des fonctions à l'image de la caméra et de renvoyer l'image modifié à la caméra
        @Override
        public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
 
            // On remplie la matrice des channels de l'image avec les couleurs RGBA
            ycc = inputFrame.rgba();
            // Imgproc.GaussianBlur(ycc, ycc, new Size(9, 9), 0);
            // Imgproc.threshold(ycc, ycc, 70, 255, Imgproc.THRESH_BINARY_INV+Imgproc.THRESH_OTSU);
 
            // Si la main est détectée
            if (handDetected) {
                //return frame;
                frame = ycc.clone();
                    // for(int i=0; i<allRoi.size(); i++){
                    // Rect roi = motionTrack(frame, allRoi.get(i), allRoiHist.get(i)); // change to frame
                    // allRoi.set(i, roi);
                    // Imgproc.rectangle(ycc, roi.tl(), roi.br(), new Scalar(255, 0, 255), 3);
                    // }
 
                /* Imgproc = traitement d'image.
                Les fonctions et structures de ce module ont trait aux transformations d'images, au filtrage, à la détection de contours, de points d'intérêt… */
                Imgproc.GaussianBlur(frame, frame, new Size(9, 9), 5); // Applique un effet de flau gaussian à l'image
                Imgproc.cvtColor(frame, frame, Imgproc.COLOR_RGB2HSV_FULL); // Convertit une image d'un espace colorimétrique à un autre.
 
                /* core = les fonctionnalités de base. Cette bibliothèque permet de manipuler les structures de base, réaliser des opérations sur des matrices, dessiner sur des images, sauvegarder et charger des données dans des fichiers XML…*/
                Core.inRange(frame, minHSV, maxHSV, frame); // Vérifie si les éléments d'un tableau sont liés avec les éléments d'un autre tableau
 
                // Point palm = getDistanceTransformCenter(frame);
                // myGLRenderer.setPos(palm.x, palm.y);
                // new: maybe move to function
                // frame = ycc.clone();
                // double avgHSV[] = getAvgHSV(frame, (int)palm.x, (int)palm.y, frame.rows(), frame.cols());
                // assignHSV(avgHSV);
 
                //TODO: check if needs to be released
                contours =  getAllContours(frame);
                int indexOfPalmContour = getPalmContour(contours);
                // Conditionnnel permettant de savoir si on affiche le cube ou pas en fonction de la détection du contour de la main ou pas
                if(indexOfPalmContour < 0)
                    myGLRenderer.setRenderCube(false);
                else{
 
                    Point palm = getDistanceTransformCenter(frame);
    //                Imgproc.circle(ycc, palm, 6, new Scalar(25, 120, 255));
                    myGLRenderer.setPos(palm.x, palm.y);
                    Rect roi = Imgproc.boundingRect(contours.get(indexOfPalmContour));
                    myGLRenderer.setCubeSize(getEuclDistance(palm, roi.tl()));
 
    //                palmContour = contours.get(indexOfPalmContour);
    //                List<Point> listHullPoints = getConvexHullPoints(palmContour);
    //                //Log.e("hull size ------>", hullPoints.size()+"");
    //                contours.clear();
    //                Point hullArray[] = new Point[listHullPoints.size()];
    //                listHullPoints.toArray(hullArray);
    //                hullPoints = new MatOfPoint(hullArray);
    //                contours.add(hullPoints);
    //                contours.add(palmContour);
    //                // draw convex hull
    //                Imgproc.drawContours(ycc, contours, 0, new Scalar(0, 255, 0));
    //                Imgproc.drawContours(ycc, contours, 1, new Scalar(0, 0, 255));
    //
    //
    //
    //                // new: maybe move to function
    ////                frame = ycc.clone();
    ////                getAvgHSV(frame);
    //
    //
    //                Imgproc.rectangle(ycc, roi.tl(), roi.br(), new Scalar(0, 0, 255), 1);
    //                Log.e("mop", contours.get(indexOfPalmContour).dims() + "    " + contours.get(0).get(0, 0).length);
    //
    //                Imgproc.convexityDefects(palmContour, hull, convexityDefects);
    //                List<Integer> defectIndices = getDefects(convexityDefects.toList());
    //                Point palmContourPoints[] = palmContour.toArray();
    ////                Log.e("defects -->", defectIndices.size()+"");
    //
    //                List<Point> defectPoints = new ArrayList<>();
    //                for(int i=0; i<defectIndices.size(); i+=4) {
    //                    Imgproc.circle(ycc, palmContourPoints[defectIndices.get(i + 2)], 6, new Scalar(255, 105, 185));
    //                    defectPoints.add(palmContourPoints[defectIndices.get(i + 2)]);
    //                }
    //                Point defectArray[] = new Point[defectPoints.size()];
    //                defectPoints.toArray(defectArray);
    //                hullPoints = new MatOfPoint(defectArray);
    //                contours.add(0, hullPoints);
    //                Imgproc.drawContours(ycc, contours, 0, new Scalar(254, 10, 0));
 
                    List<Point> hullPoints = getConvexHullPoints(contours.get(indexOfPalmContour)); //1   //indexOfPalmContour
                    fingers = getFingersTips(hullPoints, frame.rows());
                    Collections.reverse(fingers);
 
                    int fSize = fingers.size();
                    if(fSize != speedFingers){
                        speedFingers = fSize;
                        speedTime = 0;
                    }
                    else if(fSize != 5)
                        speedTime++;
                    if(speedTime > 8)
                        myGLRenderer.setCubeRotation(fSize);
                    Log.e("speed", speedTime+"  "+fSize);
 
    //                for(int i=0; i<fingers.size(); i++) {
    //                    Log.e("in f", getEuclDistance(fingers.get(i), palmCenter)+"");
    //                    Imgproc.circle(ycc, fingers.get(i), 6, new Scalar(255, 0, 0));
    //                    Imgproc.putText(ycc, fingers.get(i).x+" "+fingers.get(i).y, fingers.get(i), 1, 0.7, new Scalar(25, 0, 250) );
    //                }
 
                }
 
    //            convex defects and moment mass
    //            Imgproc.convexityDefects(maxContour, hull, convexityDefects);
    //            List<Integer> defectIndices = convexityDefects.toList();
    //
    //            Moments mont = Imgproc.moments(contours.get(0));
    //            int x = (int) (mont.get_m10() / mont.get_m00());
    //            int y = (int) (mont.get_m01() / mont.get_m00());
    //            Point palm = new Point(x, y);
    //            Imgproc.circle(ycc, palm, 6, new Scalar(25, 120, 255));
 
    //           ycc = getDistanceTransformCenter(ycc);
 
    //                contours.add(new MatOfPoint());
    //                contours.get(contours.size()-1).fromList(hullPoints);
    //                Imgproc.drawContours(frame, tempContours, tempIndex, new Scalar(0, 255, 0));
    //
    //                // Bounded Rectangle
    //                Rect roi = Imgproc.boundingRect(contours.get(indexOfMaxContour));
    //                Imgproc.rectangle(frame, roi.tl(), roi.br(), new Scalar(0, 0, 255), 3);
    //                Log.e("mop", contours.get(0).dims() + "    " + contours.get(0).get(0, 0).length);
    //
    //                 //   Rotated Rectangle
    //                RotatedRect box = Imgproc.minAreaRect(new MatOfPoint2f(contours.get(indexOfMaxContour).toArray()));
    //                Point corners[] = new Point[4];
    //                box.points(corners);
    //                for(int i=0; i<4; ++i) {
    //                    Imgproc.line(frame, corners[i], corners[(i + 1) % 4], new Scalar(255, 0, 0));
    //               }
    //            return frame;
    //            }
                return ycc;
            }
            return ycc;
        }
 
        // Fonction pour rafraichir la vue de la caméra lorsque la main n'est plus détecté
        @Override
        public void onCameraViewStopped() {
            frame.release();
            ycc.release();
            ranges.release();
            channels.release();
            dstBackProject.release();
            palmContour.release();
            hullPoints.release();
            hull.release();
            hierarchy.release();
            touchedMat.release();
            convexityDefects.release();
            nonZero.release();
            frame2.release();
            nonZeroRow.release();
            while (allRoiHist.size() > 0)
                allRoiHist.get(0).release();
            while (contours.size() > 0)
                contours.get(0).release();
        }
 
        // Méthode permettant d'agir sur pression de l'écran par l'utilisateur
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if(! handDetected){
 
                // clone and blur touched frame
                frame = ycc.clone();
                Imgproc.GaussianBlur(frame, frame, new Size(9, 9), 5);
 
                // calc x, y coords coz resolution is scaled on device display
                int x = Math.round((event.getX() - offsetFactX) * scaleFactX) ;
                int y = Math.round((event.getY() - offsetFactY) * scaleFactY);
 
                int rows = frame.rows();
                int cols = frame.cols();
 
                if ((x < 0) || (y < 0) || (x > cols) || (y > rows)) return false;
 
                palmCenter.x = x;
                palmCenter.y = y;
 
    //            int xx = (int)((0 / scaleFactX)+ offsetFactX);
    //            int yy = (int)((0 / scaleFactY)+ offsetFactY);
    //
    //            Log.e("1st", xx+"  "+yy);
    //
    //            xx = (int)((320 / scaleFactX)+ offsetFactX);
    //            yy = (int)((240 / scaleFactY)+ offsetFactY);
    //
    //            Log.e("2nd", xx+"  "+yy);
 
                // get average HSV values of a square patch around the touched pixel
                // and store them in global variables
 
                getAvgHSV(frame);
 
 
                // do below stuff in real time
 
 
    //            // to get palm center: do better coz image patch was in HSV earlier
                  // Needs work. Maybe find mean of all points
    //            Imgproc.cvtColor(frame, frame, Imgproc.COLOR_RGB2HSV_FULL);
    //            Core.inRange(frame, minHSV, maxHSV, frame);
    //
    //
    //
    //////            basePoint = getDistanceTransformCenter(ycc);
    ////            basePoint = new Point(x, y);
    ////
    //            List<MatOfPoint> contours =  getAllContours(frame);
    //            int indexOfMaxContour = getIndexOfMaxContour(contours);
    //            List<Point> hullPoints = getConvexHullPoints(contours.get(indexOfMaxContour));
    //            fingers = getFingersTips(hullPoints, rows);
    //            Collections.reverse(fingers);   // thumb is 0
    //
    //
    //
    //            //************test***********
    ////            //Imgproc.drawContours(frame, contours, indexOfMaxContour, new Scalar(255, 0, 0));
    ////            frame = ycc.clone();
    ////            Point hullArray[] = new Point[hullPoints.size()];
    ////            hullPoints.toArray(hullArray);
    ////            contours.add(new MatOfPoint(hullArray));
    ////            //contours.get(contours.size()-1).fromList(hullPoints);
    ////            Imgproc.drawContours(frame, contours, contours.size()-1, new Scalar(0, 255, 0));
    ////
    ////
    //
    //
    //
    //
    //            for(int i=0; i<fingers.size(); i++){
    //                allRoi.add(new Rect());
    //                allRoiHist.add(new Mat());
    //                assignRoiHist(fingers.get(i), ycc, allRoi.get(i), allRoiHist.get(i));
    //            }
 
 
                handDetected = true;
            }
            return false;
        }
 
        // Méthode permettant de renvoyer la liste des defauts
        protected List<Integer> getDefects(List<Integer> defectIndicesOld){
            int thresh = 800;
            int prevDepth = 0;
            List<Integer> defectIndices = new ArrayList<Integer>();
            for(int i = 0; i<defectIndicesOld.size(); i+=4) {
                int curDepth = defectIndicesOld.get(i+3);
    //            Log.e("depth", i+"  "+curDepth);
    //            if (curDepth < prevDepth)
    //                defectIndices.addAll(defectIndicesOld.subList(i-4, i));
    //            prevDepth = curDepth;
                if(curDepth > thresh)
                    defectIndices.addAll(defectIndicesOld.subList(i, i+4));
            }
            return defectIndices;
        }
 
        // Méthode permettant de gerer la fenetre et le cube ensemble
        protected Rect motionTrack(Mat frame, Rect roi, Mat roiHist){
            Imgproc.cvtColor(frame, frame, Imgproc.COLOR_RGB2HSV_FULL);
 
            List<Mat> tempList = new ArrayList<>();
            tempList.add(frame);
            Imgproc.calcBackProject(tempList, channels, allRoiHist.get(0), dstBackProject, ranges, 1);
 
            Video.meanShift(dstBackProject, roi, termCriteria);
 
            return roi;
        }
 
        // Fonction permettant de placer le rectangle et de calculer ses coordonnées x, y pour le centrer
        protected void assignRoiHist(Point point, Mat frame, Rect roi, Mat roiHist){
            int halfSide = 10;  // valeur de la moitié d'un coté
            roi.x = ((int) point.x - halfSide > 0)? (int) point.x - halfSide : 0;
            roi.y = ((int) point.y - halfSide > 0)? (int) point.y - halfSide : 0;
            roi.width = (2 * halfSide < frame.width())? 2 * halfSide : frame.width();
            roi.height = (2 * halfSide < frame.height())? 2 * halfSide : frame.height();
 
            Log.e("roi", roi.x+" "+roi.y+" "+roi.width+" "+roi.height);
 
            Mat submat = frame.submat(roi);
            Mat mask = new Mat();
            MatOfInt histSize = new MatOfInt(180);
 
            Imgproc.cvtColor(submat, submat, Imgproc.COLOR_RGB2HSV_FULL);
            Core.inRange(submat, minHSV, maxHSV, mask);
            List<Mat> tempMatList = new ArrayList();
            tempMatList.add(submat);
            Imgproc.calcHist(tempMatList, channels, mask, roiHist, histSize, ranges);
            Core.normalize(roiHist, roiHist, 0, 255, Core.NORM_MINMAX);
 
            submat.release();
            mask.release();
            histSize.release();
        }
 
        // Méthode permettant de manipuler dynamiquement l'échelle du cube en fonction de la distance avec le centre de la fentre
        protected Point getDistanceTransformCenter(Mat frame){
 
            Imgproc.distanceTransform(frame, frame, Imgproc.CV_DIST_L2, 3);
            frame.convertTo(frame, CvType.CV_8UC1);
            Core.normalize(frame, frame, 0, 255, Core.NORM_MINMAX);
            Imgproc.threshold(frame, frame, 254, 255, Imgproc.THRESH_TOZERO);
            Core.findNonZero(frame, nonZero);
 
            // are you kidding me
            int sumx = 0, sumy = 0;
            for(int i=0; i<nonZero.rows(); i++) {
                sumx += nonZero.get(i, 0)[0];
                sumy += nonZero.get(i, 0)[1];
            }
            sumx /= nonZero.rows();
            sumy /= nonZero.rows();
 
            return new Point(sumx, sumy);
        }
 
        // Méthode permettant de stocker et renvoyer une liste de point situé sur les doigts pour les détecter
        protected List<Point> getFingersTips(List<Point> hullPoints, int rows){
            // group into clusters and find distance between each cluster. distance should approx be same
            double betwFingersThresh = 80;
            double distFromCenterThresh = 80;
            double thresh = 80;
            List<Point> fingerTips  = new ArrayList<>();
            for(int i=0; i<hullPoints.size(); i++){
                Point point = hullPoints.get(i);
                if(rows - point.y < thresh){ //betwFingersThresh     // lies very near frame edge hence arm
                       // || getEuclDistance(point, palmCenter) < distFromCenterThresh) {
    //                Log.e("dist", getEuclDistance(point, palmCenter)+"");
                    continue;
                }
                if(fingerTips.size() == 0){
                    fingerTips.add(point);
                    continue;
                }
                Point prev = fingerTips.get(fingerTips.size() - 1);
                double euclDist = getEuclDistance(prev, point);
                if(getEuclDistance(prev, point) > thresh/2 &&
                        getEuclDistance(palmCenter, point) > thresh) {
    //                Log.e("be f", euclDist+"");
                    fingerTips.add(point);
                }
                if(fingerTips.size() == 5)  // prevent detection of point after thumb
                    break;
            }
            return fingerTips;
        }
 
        // Méthode permettant de calculer une distance moyenne entre les doights de la main
        protected double getEuclDistance(Point one, Point two){
            return Math.sqrt(Math.pow((two.x - one.x), 2)
                    + Math.pow((two.y - one.y), 2));
        }
 
        // Méthode permettant de renvoyer les différents points qui définisse le contour de la main
        protected List<Point> getConvexHullPoints(MatOfPoint contour){
            Imgproc.convexHull(contour, hull);
            List<Point> hullPoints = new ArrayList<>();
            for(int j=0; j < hull.toList().size(); j++){
                hullPoints.add(contour.toList().get(hull.toList().get(j)));
            }
            return hullPoints;
        }
 
        // Méthode permettant de renvoyer les différents points qui définisse le contour de la main
        protected int getPalmContour(List<MatOfPoint> contours){
 
            Rect roi;
            int indexOfMaxContour = -1;
    //        int currentMax = 0;
            for (int i = 0; i < contours.size(); i++) {
                roi = Imgproc.boundingRect(contours.get(i));
                if(roi.contains(palmCenter))
                    return i;
    //            if (contours.get(i).dims() > currentMax)
    //                indexOfMaxContour = i;
            }
            return indexOfMaxContour;
        }
 
        // Méthode permettant de renvoyer les différents points qui définisse le contour de la main
        protected List<MatOfPoint> getAllContours(Mat frame){
            frame2 = frame.clone();
            List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
            Imgproc.findContours(frame2, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
            return contours;
        }
 
        // Méthode permettant d'afficher le cube au touché
        protected void getAvgHSV(Mat frame){
            // consider square patch around touched pixel
 
            int x = (int) palmCenter.x;
            int y = (int) palmCenter.y;
            int rows = frame.rows();
            int cols = frame.cols();
 
            Rect touchedSquare = new Rect();
            int squareSide = 20;
 
            touchedSquare.x = (x > squareSide) ? x - squareSide : 0;
            touchedSquare.y = (y > squareSide) ? y - squareSide : 0;
 
            touchedSquare.width = (x + squareSide < cols) ?
                    x + squareSide - touchedSquare.x : cols - touchedSquare.x;
            touchedSquare.height = (y + squareSide < rows) ?
                    y + squareSide - touchedSquare.y : rows - touchedSquare.y;
 
            touchedMat = frame.submat(touchedSquare);
 
            // convert patch to HSV and get average values
            Imgproc.cvtColor(touchedMat, touchedMat, Imgproc.COLOR_RGB2HSV_FULL);
 
            Scalar sumHSV = Core.sumElems(touchedMat);
            int total = touchedSquare.width * touchedSquare.height;
            double avgHSV[] = {sumHSV.val[0] / total, sumHSV.val[1] / total, sumHSV.val[2] / total};
            assignHSV(avgHSV);
        }
 
        // Fonction permettant de calculer les dimensions du rectangle
        protected void assignHSV(double avgHSV[]){
            minHSV.val[0] = (avgHSV[0] > 10) ? avgHSV[0] - 10 : 0;
            maxHSV.val[0] = (avgHSV[0] < 245) ? avgHSV[0] + 10 : 255;
 
            minHSV.val[1] = (avgHSV[1] > 130) ? avgHSV[1] - 100 : 30;
            maxHSV.val[1] = (avgHSV[1] < 155) ? avgHSV[1] + 100 : 255;
 
            minHSV.val[2] = (avgHSV[2] > 130) ? avgHSV[2] - 100 : 30;
            maxHSV.val[2] = (avgHSV[2] < 155) ? avgHSV[2] + 100 : 255;
 
            Log.e("HSV", avgHSV[0]+", "+avgHSV[1]+", "+avgHSV[2]);
            Log.e("HSV", minHSV.val[0]+", "+minHSV.val[1]+", "+minHSV.val[2]);
            Log.e("HSV", maxHSV.val[0]+", "+maxHSV.val[1]+", "+maxHSV.val[2]);
        }
 
        protected Mat downSample(Mat ycc, int n){
            // TODO: erode then dilate
 
            for (int i=0; i<n; i++)
                Imgproc.pyrDown(ycc, ycc);
            return ycc;
        }
 
        // Méthode permettant de calculer et d'appliquer l'échelle du cube
        protected void setScaleFactors(int vidWidth, int vidHeight){
            float deviceWidth = javaCameraView.getWidth();
            float deviceHeight = javaCameraView.getHeight();
            if(deviceHeight - vidHeight < deviceWidth - vidWidth){
                float temp = vidWidth * deviceHeight / vidHeight;
                offsetFactY = 0;
                offsetFactX = (deviceWidth - temp) / 2;
                scaleFactY = vidHeight / deviceHeight;
                scaleFactX = vidWidth / temp;
            }
            else{
                float temp = vidHeight * deviceWidth / vidWidth;
                offsetFactX= 0;
                offsetFactY = (deviceHeight - temp) / 2;
                scaleFactX = vidWidth / deviceWidth;
                scaleFactY = vidHeight / temp;
            }
        }
    }
GLRenderer.java
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/***
 * Modification to the OpenGL sample file made by Ajinkya Dhaigude
 *
 */
 
package com.example.ajinkya.cvisionapp;
 
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.util.Log;
 
import javax.microedition.khronos.opengles.GL10;
 
public class GLRenderer implements GLSurfaceView.Renderer {
    private Cube mCube = new Cube();    // Objet Cube
    private float mCubeRotation;        // Valeur de rotation
 
    private GL10 gl;        // instancier un objet de type GL, qui nous permettra d'utiliser les fonctions OpenGL
 
    private boolean renderCube = false;
    private float XScale = 0;   // Abscisse de l'échelle du cube
    private float YScale = 0;   // Ordonnée de l'échelle du cube
    private float posX = 0;     // Abscisse de la position du cube
    private float posY = 0;     // Ordonnée de l'ordonnée du cube
    private int vidWidth = 0;
    private int vidHeight = 0;
    private float cubeSize = 1.0f;  // Valeur de la taille du cube
    private double initSizeLength = -1;
    private double rotSpeed = 0.250f;   // Valeur de la vitesse de rotation du cube
 
    // Setter pour assigner une valeur à la vitesse de rotation du cube
    public void setCubeRotation(int val){
        rotSpeed = 0.250f * val*2;
        Log.e("set", rotSpeed+"");
    }
 
    // Setter pour assigner la taille du cube
    public void setCubeSize(double sizeLength){
        if(initSizeLength < 0)
            initSizeLength = sizeLength;
        cubeSize = (float) ((sizeLength/initSizeLength));// + (sizeLength-initSizeLength));
//        Log.e("size", cubeSize+"");
    }
 
 
    public void setRenderCube(boolean val){     // not working
        renderCube = val;
    }
 
 
    // Permet d'appliquer la dimension de ...
    public void setVidDim(int w, int h){
        vidWidth = w;
        vidHeight = h;
        XScale = 11.0f * 2 / vidWidth;
        YScale = 8.0f * 2 / vidHeight;
 
//        scissor
 
    }
 
    // Fonction qu assigne les coordonnées de position X et y du cube
    public void setPos(double x, double y){
        x -= vidWidth/2;
        y -= vidHeight/2;
        posX = (float) x * XScale;
        posY = (float) y * -YScale;
        renderCube = true;
    }
 
    // Fonction permettant d'agir sur l'objet cube affiché dans la frame
    public void onDrawFrame(GL10 gl) {
        if(renderCube) {
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
            gl.glLoadIdentity();
 
 
            gl.glTranslatef(posX, posY, -90.0f);    //x=11, y =8 , z = -90
 
 
            gl.glRotatef(mCubeRotation, 1.0f, 1.0f, 1.0f); //up-down, left-right, cw-acw
 
            gl.glScalef(cubeSize, cubeSize, cubeSize);
//
//            gl.glScissor();
 
            mCube.draw(gl);
 
            gl.glLoadIdentity();
 
            mCubeRotation -= rotSpeed; //0.515f; //0.15f
        }
        else
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    }
 
    // Fonction permettatn d'agir sur le cube avec une lib javax.microedition.khronos.egl.EGLConfig
    @Override
    public void onSurfaceCreated(GL10 gl, javax.microedition.khronos.egl.EGLConfig config) {
        this.gl = gl;
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
 
        gl.glClearDepthf(1.0f);
        gl.glEnable(GL10.GL_DEPTH_TEST);
        gl.glDepthFunc(GL10.GL_LEQUAL);
 
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
                GL10.GL_NICEST);
 
    }
 
    // Fonction permetttant de gérer le changement de surface(quand la caméra bouge)
    public void onSurfaceChanged( GL10 gl, int width, int height ) {
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
////
        GLU.gluPerspective(gl, 10.0f, (float) width/ (float) height, 0.1f, 100.0f);
////
        gl.glViewport(0, 0, width, height);
//        Log.e("qweeqw", height+"  "+height);
//        this.width = width;
//        this.height = height;
 
        gl.glMatrixMode(GL10.GL_MODELVIEW);
 
        gl.glLoadIdentity();
    }
}
Cube.java
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/***
 *
 *  Cube implementation as provided by the OpenGL sample library
 *
 *
 */
 
package com.example.ajinkya.cvisionapp;
 
import java.nio.ByteBuffer;
import java.nio.ByteOrder;      // Retrieves this buffer's byte order.
import java.nio.FloatBuffer;
 
import javax.microedition.khronos.opengles.GL10;
 
public class Cube {
 
    private FloatBuffer mVertexBuffer;
    private FloatBuffer mColorBuffer;   //Creates a view of this byte buffer as a float buffer.
    private ByteBuffer mIndexBuffer;    //Creates a new, read-only byte buffer that shares this buffer's content.
 
    private float vertices[] = {
            -1.0f, -1.0f, -1.0f,
            1.0f, -1.0f, -1.0f,
            1.0f,  1.0f, -1.0f,
            -1.0f, 1.0f, -1.0f,
            -1.0f, -1.0f,  1.0f,
            1.0f, -1.0f,  1.0f,
            1.0f,  1.0f,  1.0f,
            -1.0f,  1.0f,  1.0f
    };
    private float colors[] = {
            0.0f,  1.0f,  0.0f,  1.0f,
            0.0f,  1.0f,  0.0f,  1.0f,
            1.0f,  0.5f,  0.0f,  1.0f,
            1.0f,  0.5f,  0.0f,  1.0f,
            1.0f,  0.0f,  0.0f,  1.0f,
            1.0f,  0.0f,  0.0f,  1.0f,
            0.0f,  0.0f,  1.0f,  1.0f,
            1.0f,  0.0f,  1.0f,  1.0f
    };
 
    private byte indices[] = {
            0, 4, 5, 0, 5, 1,
            1, 5, 6, 1, 6, 2,
            2, 6, 7, 2, 7, 3,
            3, 7, 4, 3, 4, 0,
            4, 7, 6, 4, 6, 5,
            3, 0, 1, 3, 1, 2
    };
 
    public Cube() {
        ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);    // Renvoie un buffer direct (pour buffer avec taille et durée importantes)
        byteBuf.order(ByteOrder.nativeOrder());
        mVertexBuffer = byteBuf.asFloatBuffer();
        mVertexBuffer.put(vertices);
        mVertexBuffer.position(0);
 
        byteBuf = ByteBuffer.allocateDirect(colors.length * 4);
        byteBuf.order(ByteOrder.nativeOrder());
        mColorBuffer = byteBuf.asFloatBuffer();
        mColorBuffer.put(colors);
        mColorBuffer.position(0);
 
        mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
        mIndexBuffer.put(indices);
        mIndexBuffer.position(0);
    }
 
    // Méthode permettant de dessiner le cube
    public void draw(GL10 gl) {
        gl.glFrontFace(GL10.GL_CW);
 
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
        gl.glColorPointer(4, GL10.GL_FLOAT, 0, mColorBuffer);
 
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
 
        gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE, mIndexBuffer);
 
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
    }
}
une bonne soirée à vous,