private static Mat rodr2quat(Mat rodr) {
    double t = Core.norm(rodr);
    double[] r = new double[3];
    rodr.get(0, 0, r);

    double[] quat = {
      Math.cos(t / 2),
      Math.sin(t / 2) * r[0] / t,
      Math.sin(t / 2) * r[1] / t,
      Math.sin(t / 2) * r[2] / t
    };
    Mat quatm = new Mat(4, 1, CvType.CV_64F);
    quatm.put(0, 0, quat);
    return quatm;
  }
  /**
   * Analyze video frames using computer vision approach and generate a ArrayList<AttitudeRec>
   *
   * @param recs output ArrayList of AttitudeRec
   * @return total number of frame of the video
   */
  private int analyzeVideo(ArrayList<AttitudeRec> recs) {
    VideoMetaInfo meta = new VideoMetaInfo(new File(mPath, "videometa.json"));

    int decimation = 1;

    if (meta.fps > DECIMATION_FPS_TARGET) {
      decimation = (int) (meta.fps / DECIMATION_FPS_TARGET);
      meta.fps /= decimation;
    }

    VideoDecoderForOpenCV videoDecoder =
        new VideoDecoderForOpenCV(
            new File(mPath, "video.mp4"), decimation); // every 3 frame process 1 frame

    Mat frame;
    Mat gray = new Mat();
    int i = -1;

    Size frameSize = videoDecoder.getSize();

    if (frameSize.width != meta.frameWidth || frameSize.height != meta.frameHeight) {
      // this is very unlikely
      return -1;
    }

    if (TRACE_VIDEO_ANALYSIS) {
      Debug.startMethodTracing("cvprocess");
    }

    Size patternSize = new Size(4, 11);

    float fc = (float) (meta.frameWidth / 2.0 / Math.tan(meta.fovWidth / 2.0));
    Mat camMat = cameraMatrix(fc, new Size(frameSize.width / 2, frameSize.height / 2));
    MatOfDouble coeff = new MatOfDouble(); // dummy

    MatOfPoint2f centers = new MatOfPoint2f();
    MatOfPoint3f grid = asymmetricalCircleGrid(patternSize);
    Mat rvec = new MatOfFloat();
    Mat tvec = new MatOfFloat();

    MatOfPoint2f reprojCenters = new MatOfPoint2f();

    if (LOCAL_LOGV) {
      Log.v(TAG, "Camera Mat = \n" + camMat.dump());
    }

    long startTime = System.nanoTime();

    while ((frame = videoDecoder.getFrame()) != null) {
      if (LOCAL_LOGV) {
        Log.v(TAG, "got a frame " + i);
      }

      // has to be in front, as there are cases where execution
      // will skip the later part of this while
      i++;

      // convert to gray manually as by default findCirclesGridDefault uses COLOR_BGR2GRAY
      Imgproc.cvtColor(frame, gray, Imgproc.COLOR_RGB2GRAY);

      boolean foundPattern =
          Calib3d.findCirclesGridDefault(
              gray, patternSize, centers, Calib3d.CALIB_CB_ASYMMETRIC_GRID);

      if (!foundPattern) {
        // skip to next frame
        continue;
      }

      if (OUTPUT_DEBUG_IMAGE) {
        Calib3d.drawChessboardCorners(frame, patternSize, centers, true);
      }

      // figure out the extrinsic parameters using real ground truth 3D points and the pixel
      // position of blobs found in findCircleGrid, an estimated camera matrix and
      // no-distortion are assumed.
      boolean foundSolution =
          Calib3d.solvePnP(grid, centers, camMat, coeff, rvec, tvec, false, Calib3d.CV_ITERATIVE);

      if (!foundSolution) {
        // skip to next frame
        if (LOCAL_LOGV) {
          Log.v(TAG, "cannot find pnp solution in frame " + i + ", skipped.");
        }
        continue;
      }

      // reproject points to for evaluation of result accuracy of solvePnP
      Calib3d.projectPoints(grid, rvec, tvec, camMat, coeff, reprojCenters);

      // error is evaluated in norm2, which is real error in pixel distance / sqrt(2)
      double error = Core.norm(centers, reprojCenters, Core.NORM_L2);

      if (LOCAL_LOGV) {
        Log.v(TAG, "Found attitude, re-projection error = " + error);
      }

      // if error is reasonable, add it into the results
      if (error < REPROJECTION_THREASHOLD) {
        double[] rv = new double[3];
        rvec.get(0, 0, rv);
        recs.add(new AttitudeRec((double) i / meta.fps, rodr2rpy(rv)));
      }

      if (OUTPUT_DEBUG_IMAGE) {
        Calib3d.drawChessboardCorners(frame, patternSize, reprojCenters, true);
        Highgui.imwrite(
            Environment.getExternalStorageDirectory().getPath()
                + "/RVCVRecData/DebugCV/img"
                + i
                + ".png",
            frame);
      }
    }

    if (LOCAL_LOGV) {
      Log.v(TAG, "Finished decoding");
    }

    if (TRACE_VIDEO_ANALYSIS) {
      Debug.stopMethodTracing();
    }

    if (LOCAL_LOGV) {
      // time analysis
      double totalTime = (System.nanoTime() - startTime) / 1e9;
      Log.i(TAG, "Total time: " + totalTime + "s, Per frame time: " + totalTime / i);
    }
    return i;
  }
Esempio n. 3
0
  /**
   * Appelée à chaque nouvelle prise de vue par la caméra.
   *
   * <p>Son comportement sera différent suivant ce que l'on cherche à faire :
   *
   * <ul>
   *   <li>Si la porte n'est pas stable, on cherche alors à détecter l'événement porte stable pour
   *       pouvoir prendre une photo.
   *   <li>Si la porte est stable mais pas fermée, cela signifie que l'on a déjà pris une photo du
   *       contenu du frigo et on attend que la porte soit fermée pour revenir dans l'état initial.
   * </ul>
   *
   * @param inputFrame Image captée par la caméra
   */
  public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
    Mat current = inputFrame.rgba();
    if (stable && !fermee) {
      // Une photo a été prise
      // On va rechercher l'événement : le flux vidéo représente des images noires
      Scalar scalaireN = new Scalar(0x00, 0x00, 0x00, 0xFF);
      Mat noir = new Mat(current.size(), current.type(), scalaireN);
      // noir est une matrice noire
      // Comparaison avec une image noire, résultat stocké dans une matrice diffNoir
      Mat diffNoir = new Mat(current.size(), current.type());
      Core.absdiff(current, noir, diffNoir);
      Double normeDiffNoir =
          new Double(Core.norm(diffNoir)); // Calclule de la norme de cette matrice
      n.add(normeDiffNoir); // Ajout de cette norme dans un conteneur
      compteur++; // Compteur du nombre d'images prises
      if (compteur > 11) {
        // S'il y a suffisamment d'images déjà prises, on vérifie que la porte est fermée
        fermee = true;
        int i = 0;
        while (fermee && i < 10) {
          // La porte est fermee si sur les dix dernières photos prises, la différence
          // entre une image noire et l'image current n'est pas trop grande.
          if (n.get(compteur - 1 - i) > 4500) {
            fermee =
                false; // Si cette différence est trop grande, on considère que la porte n'est pas
            // fermée
          }
          i++;
        } // Si elle n'a jamais été trop grande, la porte est effectivement fermée
        if (fermee) {
          // Remise à 0 du compteur s'il doit être réutilisé pour une nouvelle photo
          // De même pour le tableau n
          compteur = 0;
          n.clear();
          finish(); // Retour sur l'activité principale qui attend une ouverture du frigo.
        }
      }
    } else if (!stable) {
      // Aucune photo n'a encore été prise
      // On va rechercher l'événement : l'image est stable
      if (buffer == null) { // Première image reçue, il faut créer une matrice buffer qui contiendra
        // l'image précédente
        buffer = new Mat(current.size(), current.type());
        buffer = current.clone();
      } else { // C'est au moins la deuxième image reçue
        // Comparaison entre l'image précédente et l'image courante, résultat stocké dans une
        // matrice diffBuffer
        Mat diffBuffer = new Mat(current.size(), current.type());
        Core.absdiff(current, buffer, diffBuffer);
        Double normeDiffBuffer =
            new Double(Core.norm(diffBuffer)); // Calcul de la norme de cette matrice
        n.add(normeDiffBuffer); // Ajout de cette norme dans un conteneur
        compteur++; // Compteur du nombre d'images prises
        if (compteur > 11) {
          // S'il y a suffisamment d'images déjà prises, on vérifie que la porte est stable
          stable = true;
          int i = 0;
          while (stable && i < 10) {
            // On est stable si sur les dix dernières prises, la différence entre
            // l'image current est l'image stockée n'est pas trop grande
            if (n.get(compteur - 1 - i) > 4500) {
              stable = false;
            }
            i++;
          }
          if (stable) {
            Log.i(TAG, "Prise de la photo");
            // Si l'image est stable, il faut vérifier tout d'abord que la porte n'est pas fermée.
            // (on effectue ici le même traîtement que pour une détection de porte fermée)
            Scalar scalaireN = new Scalar(0x00, 0x00, 0x00, 0xFF);
            Mat noir = new Mat(current.size(), current.type(), scalaireN);
            Mat diffNoir = new Mat(current.size(), current.type());
            Core.absdiff(current, noir, diffNoir);
            Double normeDiffNoir = new Double(Core.norm(diffNoir));
            if (normeDiffNoir > 4500) {
              // Si la porte n'est pas fermée, on va sauvegarder l'image avant de l'envoyer
              File pictureFileDir = getDir();
              SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy-HH.mm.ss");
              String date = dateFormat.format(new Date());
              String photoFile = "PictureCV_" + date + ".jpg"; // Nom du fichier
              String filename = pictureFileDir.getPath() + File.separator + photoFile;
              // On doit convertir les couleurs avant de sauvegarder l'image.
              // La description de la fonction cvtColor explique pourquoi
              Imgproc.cvtColor(current, current, Imgproc.COLOR_BGR2RGB);
              Highgui.imwrite(filename, current); // Sauvegarde
              Log.i(TAG, "Photo sauvegardée");
              // Remise à 0 du compteur s'il doit être réutilisé pour une nouvelle photo
              // De même pour le tableau n
              compteur = 0;
              n.clear();

              /*
              //Tentative de reconnaissance d'image
              //On va essayer de détecter la présence d'une banane pour chaque nouvelle image
                	//captée par le téléphone
                	Mat Grey = inputFrame.gray(); //Image prise par la caméra
                	MatOfRect bananas = new MatOfRect();
                	Size minSize = new Size(30,20);
                	Size maxSize = new Size(150,100);
                	Log.i(TAG, "Tentative de détection de banane");
                	mCascadeClassifier.detectMultiScale(Grey, bananas, 1.1, 0, 10,minSize,maxSize);
                	if (bananas.rows()>0){
                		Log.i(TAG, "Nombre de bananes détectées : " + bananas.rows());
                	}
              envoiPhoto(filename, bananas.rows()); //Envoi de la photo avec les données de reconnaissance
              //Fin de la reconnaissance de l'image
              */

              envoiPhoto(filename); // Envoi de la photo sans les données de reconnaissance

            } else {
              // Cas où a porte est fermée
              // Remise à 0 du compteur s'il doit être réutilisé pour une nouvelle photo
              // De même pour le tableau n
              compteur = 0;
              n.clear();
              finish();
            }
          }
        }
        buffer = current.clone();
      }
    }
    return inputFrame.rgba();
  }