2016-11-07 2 views
3

Je compare deux images à l'aide de findHomography(). J'ai ajouté des modules supplémentaires de opencv_contrib dans OpenCV 3.1.0 utiliser des algorithmes Surf et tamise et de compiler pour les dernières architectures Android. Je peux compiler avec succès les bibliothèques en utilisant ndk-build.Erreur lors de la lecture des images à l'aide d'imread OpenCV

Problème: Quand je lance l'application sur LG Nexus 5, je suis capable de lire des images en utilisant imread mais quand je lance la même application sur LG Nexus 5X, imread ne lit pas l'image. J'ai testé sur Samsung S6 et OnePlus X et ont le même problème. Ci-dessous ma méthode native:

#include <jni.h> 
#include <string.h> 
#include <stdio.h> 
#include <android/log.h> 

#include "opencv2/core/core.hpp" 
#include "opencv2/features2d/features2d.hpp" 
#include "opencv2/highgui/highgui.hpp" 
#include "opencv2/calib3d/calib3d.hpp" 
#include "opencv2/xfeatures2d/nonfree.hpp" 
#include "opencv2/opencv.hpp" 

using namespace std; 
using namespace cv; 

#define LOG_TAG "nonfree_jni" 
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) 

jboolean detect_features(JNIEnv * env, jstring scenePath, jstring objectPath) { 

    const char *nativeScenePath = (env)->GetStringUTFChars(scenePath, NULL); 
    const char *nativeObjectPath = (env)->GetStringUTFChars(objectPath, NULL); 

    nativeScenePath = env->GetStringUTFChars(scenePath, 0); 
    nativeObjectPath = env->GetStringUTFChars(objectPath, 0); 

    (env)->ReleaseStringUTFChars(scenePath, nativeScenePath); 
    (env)->ReleaseStringUTFChars(objectPath, nativeObjectPath); 

    __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "Object path: ----- %s \n", nativeObjectPath); 
    __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "Scene path: ----- %s \n", nativeScenePath); 

    Mat img_object = imread(nativeObjectPath, CV_LOAD_IMAGE_GRAYSCALE); 
    Mat img_scene = imread(nativeScenePath, CV_LOAD_IMAGE_GRAYSCALE); 


    if(!img_object.data || !img_scene.data){ 
     LOGI(" --(!) Error reading images "); 
     return false; 
    } 

     //-- Step 1: Detect the keypoints using SURF Detector 
     int minHessian = 400; 

    __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "Image comparison rows: ----- %d \n", img_object.rows); 
    __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "Image comparison colums: ----- %d \n", img_object.cols); 

//  cv::xfeatures2d::SurfFeatureDetector detector(minHessian); 
     Ptr<cv::xfeatures2d::SurfFeatureDetector> detector = cv::xfeatures2d::SurfFeatureDetector::create(minHessian); 

     std::vector<KeyPoint> keypoints_object, keypoints_scene; 
     detector->detect(img_object, keypoints_object); 
     detector->detect(img_scene, keypoints_scene); 

     //-- Step 2: Calculate descriptors (feature vectors) 
//  cv::xfeatures2d::SurfDescriptorExtractor extractor; 
     Ptr<cv::xfeatures2d::SurfDescriptorExtractor> extractor = cv::xfeatures2d::SurfDescriptorExtractor::create(); 

     Mat descriptors_object, descriptors_scene; 

     extractor->compute(img_object, keypoints_object, descriptors_object); 
     extractor->compute(img_scene, keypoints_scene, descriptors_scene); 

     //-- Step 3: Matching descriptor vectors using FLANN matcher 
     FlannBasedMatcher matcher; 
     std::vector<DMatch> matches; 
     matcher.match(descriptors_object, descriptors_scene, matches); 

     double max_dist = 0; double min_dist = 100; 

     //-- Quick calculation of max and min distances between keypoints 
     for(int i = 0; i < descriptors_object.rows; i++) 
     { 
      double dist = matches[i].distance; 
      if (dist == 0) continue; 
      if(dist < min_dist) min_dist = dist; 
      if(dist > max_dist) max_dist = dist; 
     } 

     __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "-- Max dist : %f \n", max_dist); 
     __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "-- Min dist : %f \n", min_dist); 

     //-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist) 
     std::vector<DMatch> good_matches; 

     for(int i = 0; i < descriptors_object.rows; i++) 
     { 
      if(matches[i].distance <= 0.1) //3*min_dist 
      { 
       good_matches.push_back(matches[i]); 
      } 
     } 

     __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "FLANN total matches -----: %zu \n", matches.size()); 
     __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "FLANN good matches -----: %zu \n", good_matches.size()); 

     Mat img_matches; 
     drawMatches(img_object, keypoints_object, img_scene, keypoints_scene, 
        good_matches, img_matches, Scalar::all(-1), Scalar::all(-1), 
        vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); 

     //-- Localize the object 
     std::vector<Point2f> obj; 
     std::vector<Point2f> scene; 

     for(int i = 0; i < good_matches.size(); i++) 
     { 
      //-- Get the keypoints from the good matches 
      obj.push_back(keypoints_object[ good_matches[i].queryIdx ].pt); 
      scene.push_back(keypoints_scene[ good_matches[i].trainIdx ].pt); 
     } 

     if (good_matches.size() >= 5) 
     { 
      Mat H = findHomography(obj, scene, CV_RANSAC); 

      //-- Get the corners from the image_1 (the object to be "detected") 
      std::vector<Point2f> obj_corners(4); 
      obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint(img_object.cols, 0); 
      obj_corners[2] = cvPoint(img_object.cols, img_object.rows); obj_corners[3] = cvPoint(0, img_object.rows); 
      std::vector<Point2f> scene_corners(4); 

      Mat output, matrix; 

      warpPerspective(img_object, output, H, { img_scene.cols, img_scene.rows }); 

      //////////////////////////////////////////////////////////////////////////////// 

      detector->detect(output, keypoints_object); 

      //-- Step 2: Calculate descriptors (feature vectors) 
      //cv::xfeatures2d::SurfDescriptorExtractor extractor; 
      Ptr<cv::xfeatures2d::SurfDescriptorExtractor> extractor = cv::xfeatures2d::SurfDescriptorExtractor::create(); 

      extractor->compute(output, keypoints_object, descriptors_object); 
      extractor->compute(img_scene, keypoints_scene, descriptors_scene); 

      std::vector<std::vector<cv::DMatch>> matches2; 
      BFMatcher matcher; 
      matcher.knnMatch(descriptors_object, descriptors_scene, matches2, 2); 
      vector<cv::DMatch> good_matches2; 

      for (int i = 0; i < matches2.size(); ++i) 
      { 
       const float ratio = 0.8; // As in Lowe's paper; can be tuned 
       if (matches2[i][0].distance < ratio * matches2[i][1].distance) 
       { 
        good_matches2.push_back(matches2[i][0]); 
       } 
      } 

      if (matches2.size() == 0 || good_matches2.size() == 0) { 
      LOGI("End run!\n"); 
       return false; 
      } 

      double ratioOfSimilarity = static_cast<double>(good_matches2.size())/static_cast<double>(matches2.size()); 

      __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "Bruteforce total matches -----: %zu \n", matches2.size()); 
      __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "Bruteforce good matches -----: %zu \n", good_matches2.size()); 
      __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, "Bruteforce similarity ratio -----: %f \n", ratioOfSimilarity); 

      if(ratioOfSimilarity >= 0.3) { 
      LOGI("End run!\n"); 
       return true; 
      } 

      LOGI("End run!\n"); 
      return false; 

     } 
     LOGI("End run!\n"); 
     return false; 
} 

et les sauts de méthode à cette ligne:

if(!img_object.data || !img_scene.data){ 
     LOGI(" --(!) Error reading images "); 
     return false; 
} 
+0

Les appareils testés qui ne lisent pas l'image ont Android 6.0? – uelordi

+0

@uelordi Oui certains ont Android 6.0 et certains ont Android 7.0. Mais j'ai testé sur Nexus 5 avec android 6.0.1 et ça marche. – Shahzeb

+0

ok, donc ce n'est pas le problème d'autorisation d'exécution. lisez-vous les images de/sdcard? dans le stockage interne apk? – uelordi

Répondre

4

Je teste votre problème imread sur appareil Android Nexus 5x 7.0, donc je n'ai pris le commandement imread dans mon projet Android.

Mes bibliothèques opencv sont des bibliothèques préconfigurées OpenCV 3.1.0.

Après quelques tests, je ne peux lire l'image dans le nexus 5x:

  • /sdcard OK
  • /stockage/émulé/0/Ne parvient pas

Je pense que sont en fait les même chemin mais il ne charge pas l'image avec la deuxième option. Dans mon expérience de développement, j'ai eu des problèmes avec les chemins de stockage externes, car certains périphériques ont un stockage externe émulé et d'autres non.

Donc généralement, pour éviter ce problème, je copie mes ressources internes .APK en temps d'exécution.

je stocke mes ressources sur le dossier res.raw et je reçois le chemin interne avec

config_path = m_context.getApplicationContext().getFilesDir().toString(); 

J'espère que mon test aide à résoudre votre problème.

Cheers.

Unai.

+1

J'apprécie vraiment vos efforts. Vous ne croirez pas quel était le problème. J'avais en fait copié des images du dossier "brut" vers la carte SD. Le problème était, leurs noms étaient courts (comme ad_0.png). Je les ai renommés avec un nom plus long et cela a commencé à fonctionner. C'est étrange. De toute façon, votre point semble aussi valide. Merci beaucoup! – Shahzeb

+0

vous êtes les bienvenus :) – uelordi

0

shouldn ce soit !img_object.data? Maintenant vous vous connectez une erreur et renvoyez false quand il y a des données au lieu de quand vous n'avez pas de données.

+0

Désolé, c'était une faute de frappe. Comme je l'ai mentionné plus tôt, cela fonctionne sur certains appareils mais pas sur tous. – Shahzeb