2016-11-07 1 views
3

findHomography()를 사용하여 두 이미지를 비교하고 있습니다. 나는 서핑엄밀히알고리즘을 사용하고 최신 안드로이드 아키텍처 컴파일 에서 OpenCV 3.1.0opencv_contrib에서 추가 모듈을 추가했습니다. ndk-build을 사용하여 라이브러리를 성공적으로 컴파일 할 수 있습니다.imread OpenCV를 사용하여 이미지를 읽는 중 오류가 발생했습니다.

문제 : LG 넥서스 5에 응용 프로그램을 실행할 때 , 나는 imread을 사용하여 이미지를 읽을 수 있어요하지만 5 배LG 넥서스에서 동일한 응용 프로그램을 실행할 때, imread 이미지를 읽지 않습니다. 나는 삼성 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

이미지를 읽지 않은 테스트 된 장치는 android 6.0? – uelordi

+0

@uelordi 예 일부는 android 6.0이 있고 일부는 android 7.0이 있습니다. 하지만 넥서스 5에서 안드로이드 6.0.1을 테스트 해 보았습니다. – Shahzeb

+0

ok이므로 런타임 권한 문제는 아닙니다./sdcard에서 이미지를 읽으십니까? apk 내부 저장소에 있습니까? – uelordi

답변

4

나는 Nexus 5x android 7.0 장치에서 의 imread 문제를 테스트하므로 안드로이드 프로젝트에서만 imread 명령을 사용했습니다.

내 opencv 라이브러리는 OpenCV 3.1.0 미리 만들어진 라이브러리입니다.

는 몇 가지 테스트 후, 나는 단지 넥서스 5 배의 이미지를 읽을 수 있습니다

  • /sdcard에 OK
  • /저장// 0 에뮬레이션/I 실제로 생각입니다

실패 같은 경로이지만 두 번째 옵션으로 이미지를로드하지 않습니다.

일부 장치는 외부 저장소와 다른 제품을 에뮬레이션했기 때문에 외부 저장소 경로에 문제가있었습니다.

일반적으로이 문제를 피하기 위해 리소스를 실행 시간에 내부 .APK로 복사합니다.

나는 res.raw 폴더 내 자원을 저장하고 난 내 테스트 문제를 해결하는 데 도움이되기를 바랍니다

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

와 내부 경로를 얻을.

건배.

우 나이.

+1

정말 고맙습니다. 문제가 무엇인지 믿지 않을 것입니다. 나는 실제로 원본 폴더에서 sdcard로 이미지를 복사했다. 문제는 이름이 짧았습니다 (예 : ad_0.png). 나는 더 긴 이름으로 그들을 개명하고 그것은 일하기 시작했다. 그건 이상 하네. 어쨌든, 당신의 요점은 유효합니다. 고마워요! – Shahzeb

+0

당신은 환영합니다 :) – uelordi

0

Shouldn 그 !img_object.data 수 아래 내 기본 방법입니다? 이제 데이터가 없을 때 대신 데이터가있을 때 오류를 기록하고 false를 반환합니다.

+0

죄송합니다. 오타되었습니다. 앞에서 언급했듯이 일부 장치에서는 작동하지만 모든 장치에서는 작동하지 않습니다. – Shahzeb

관련 문제