2016-11-07 5 views
3

findHomography()を使用して2つの画像を比較しています。私はサーフふるいにかけるアルゴリズムを使用すると、最新のAndroidのアーキテクチャ用にコンパイルするOpenCVの3.1.0opencv_contribから余分なモジュールを追加しました。 ndk-buildを使用してライブラリを正常にコンパイルできます。imreadを使用して画像を読み取るときにエラーが発生するOpenCV

問題: 私はLG Nexus 5の上でアプリケーションを実行すると、私はimreadを使用して画像を読み取ることができていますが、私はLGネクサス5Ximread上で同じアプリケーションを実行すると、画像を読み取れません。私はサムスンS6OnePlus Xでテストして同じ問題があります。

#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; 
} 

と、この行のメソッドブレーク:

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

イメージを読み取っていないテスト済みのデバイスには、アンドロイド6.0? – uelordi

+0

@uelordiはいいくつかはアンドロイド6.0を持っていて、いくつかはアンドロイド7.0を持っています。しかし、アンドロイド6.0.1でnexus 5をテストしたところ、動作しています。 – Shahzeb

+0

okです。したがって、実行時のアクセス権の問題ではありません。あなたは/ sdcardから画像を読んでいますか? apkの内部ストレージに? – uelordi

答えて

4

Nexus 5x android 7.0デバイスのimread問題をテストします。 ですので、私のAndroidプロジェクトではimreadコマンドしか使用していません。

私のopencvライブラリは、OpenCV 3.1.0の事前ビルドされたライブラリです。

いくつかのテストの後、私はネクサス5倍で画像を読み取ることができます。

  • /SDカードOK
  • /ストレージ/は/ 0 /は

を失敗し、私は実際にあると思いエミュレート同じパスを使用しますが、2番目のオプションでイメージをロードしません。

Mat flag=imread("/sdcard/Pictures/mytest.jpg", CV_LOAD_IMAGE_GRAYSCALE); 

私の開発経験では、一部のデバイスが外部ストレージをエミュレートしているため、外部ストレージパスに問題がありました。

通常、この問題を回避するため、実行時に自分のリソースを内部の.APKにコピーします。

私はres.rawフォルダに私のリソースを格納し、私は私のテストは、あなたの問題を解決するのに役立ちます願っています

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

と内部パスを取得します。

乾杯。

Unai。

+1

本当にありがとうございます。あなたはその問題が何かを信じません。私は実際には "raw"フォルダからsdcardにイメージをコピーしました。問題は、名前が短いことです(ad_0.pngなど)。私は長い名前でそれらの名前を変更し、それは働き始めた。それは変です。とにかく、あなたのポイントは有効すぎるようです。どうもありがとう! – Shahzeb

+0

あなたは歓迎です:) – uelordi

0

Shouldnそれは!img_object.dataこと以下は私のネイティブメソッドのですか? これで、データを持たないときにデータがあるときにエラーを記録し、falseを返すようになりました。

+0

申し訳ありませんが、それはタイプミスでした。先に述べたとおり、一部のデバイスでは動作しますが、すべてでは動作しません。 – Shahzeb

関連する問題