2014-02-18 3 views
4

Мой проект - это признание листа на Android с использованием библиотеки OpenCV. Я использую обнаружение ORB, чтобы получить ключевую точку изображения и использовать дескриптор ORB, чтобы получить функцию ключевой точки. Это код, который я использую:Как сохранить функции OpenCV Keypoint в базе данных?

bmp=BitmapFactory.decodeResource(getResources(),R.drawable.t1); 
Utils.bitmapToMat(bmp, mat); 
FeatureDetector detector = FeatureDetector.create(FeatureDetector.ORB); 
detector.detect(mat, keypoints); 
DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.ORB); 
extractor.compute(mat, keypoints, features); 

Источник: http://answers.opencv.org/question/6260/orb-features/

Но каждый я вход тот же образ, Keypoint этого образа всегда разные. Могу ли я сохранить функцию keypoint в базе данных, если это всегда отличается? Или я должен сохранить изображение, чтобы сохранить данные функции? Если это можно сохранить в базе данных, как я могу это сделать?

+3

Просто заметил, что этот вопрос в основном дублируется: http://stackoverflow.com/q/15271411/1085483 –

+0

@RuiMarques: Значит, вы должны указывать его как дубликат, а не копировать свой ответ здесь дословно. – chappjc

+0

На самом деле я ответил здесь первым. Я не мог это обозначить, потому что у другого есть голосование или принятые ответы. –

ответ

4

На мой взгляд, самый универсальный способ хранения ключевых точек - сначала преобразовать их в формат обмена данными, такой как JSON.

После того, как вы сможете сделать это преобразование, у вас есть много возможностей для его хранения. JSON легко преобразовывается в строку и/или отправляется через сетевое соединение.

С OpenCV C++ you are able to store data as YAML, но это еще не доступно для Android.

Для анализа JSON на Java вы можете использовать этот простой в использовании library Google GSON.

И вот моя первая попытка сделать именно это:

public static String keypointsToJson(MatOfKeyPoint mat){ 
    if(mat!=null && !mat.empty()){   
     Gson gson = new Gson(); 

     JsonArray jsonArr = new JsonArray();    

     KeyPoint[] array = mat.toArray(); 
     for(int i=0; i<array.length; i++){ 
      KeyPoint kp = array[i]; 

      JsonObject obj = new JsonObject(); 

      obj.addProperty("class_id", kp.class_id); 
      obj.addProperty("x",  kp.pt.x); 
      obj.addProperty("y",  kp.pt.y); 
      obj.addProperty("size",  kp.size); 
      obj.addProperty("angle", kp.angle);       
      obj.addProperty("octave", kp.octave); 
      obj.addProperty("response", kp.response); 

      jsonArr.add(obj);    
     } 

     String json = gson.toJson(jsonArr);   

     return json; 
    } 
    return "{}"; 
} 

public static MatOfKeyPoint keypointsFromJson(String json){ 
    MatOfKeyPoint result = new MatOfKeyPoint(); 

    JsonParser parser = new JsonParser(); 
    JsonArray jsonArr = parser.parse(json).getAsJsonArray();   

    int size = jsonArr.size(); 

    KeyPoint[] kpArray = new KeyPoint[size]; 

    for(int i=0; i<size; i++){ 
     KeyPoint kp = new KeyPoint(); 

     JsonObject obj = (JsonObject) jsonArr.get(i); 

     Point point = new Point( 
       obj.get("x").getAsDouble(), 
       obj.get("y").getAsDouble() 
     );   

     kp.pt  = point; 
     kp.class_id = obj.get("class_id").getAsInt(); 
     kp.size  =  obj.get("size").getAsFloat(); 
     kp.angle = obj.get("angle").getAsFloat(); 
     kp.octave = obj.get("octave").getAsInt(); 
     kp.response = obj.get("response").getAsFloat(); 

     kpArray[i] = kp; 
    } 

    result.fromArray(kpArray); 

    return result; 
} 
+0

спасибо за ответ. Теперь я хочу знать, что ключевое слово Property (class_id/x/y/size/angle/octave/response), которое я должен сохранить в базе данных? я действительно не понимаю о ключевой точке. –

+0

Почему бы не сохранить все? –

+0

ОК, я понимаю сейчас. Но я смущен тем, какие данные я должен сохранять в базе данных, ключевой точке или функции? Я использую ваш ответ о сохранении конвертировать Mat в Json здесь: http://answers.opencv.org/question/8873/best-way-to-store-a-mat-object-in-android/ Но я не знаю, Понимаете ли вы о «типе» и «данных», можете ли вы мне помочь? Спасибо до –

0

Недавно я заканчиваю проект о признании человеческого жеста. Но я использовал svm из openCv. для вашего номера ключевого пункта информирования в каждом изображении это его основная точка (согласно определению openCv). для распознавания или, другими словами, «предсказания», вы должны сохранить функцию ключевой точки (свойство Keypoint), которое является матом. Я использовал SURF и вычислил 64 функции для каждой ключевой точки. Надеюсь, это поможет.

0

Хотя я не запускал тайминги, я подозреваю, что для прохождения таких форматов, как XML или JSON, потребуется больше пространства и вычислительных ресурсов, чем использование примитивов.

Ниже приведен код, который можно использовать для сохранения и извлечения базы данных MatOfKeyPoint в SQLite в среде Android. Это использует OpenCV 2.4.11, поэтому SIFT доступен.

То, что вы видите при запуске этого приложения, - это тестовое изображение (которое вам нужно предоставить и разместить в выпадающей папке) с добавленными ключевыми точками.

Метод siftTest() начинается с вычисления keyPoints который MatOfKeyPoint типа. Код сохраняет базовые данные этого объекта в базе данных, затем считывает данные и создает новый объект keyPointsFromDb, содержимое которого применяется к исходному изображению, и результат отображается.

public class MainActivity extends AppCompatActivity { 
    static { 
     System.loadLibrary("native-lib"); 
     System.loadLibrary("opencv_java"); 
     System.loadLibrary("nonfree"); 

    } 
    private ImageView imageView; 
    private Bitmap inputImage; // make bitmap from image resource 
    private FeatureDetector detector = FeatureDetector.create(FeatureDetector.SIFT); 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     inputImage = BitmapFactory.decodeResource(getResources(), R.drawable.test); 
     imageView = (ImageView) this.findViewById(R.id.imageView); 
     siftTest(); 
    } 

    public void siftTest() { 
     Mat rgba = new Mat(); 
     Utils.bitmapToMat(inputImage, rgba); 
     MatOfKeyPoint keyPoints = new MatOfKeyPoint(); 
     Imgproc.cvtColor(rgba, rgba, Imgproc.COLOR_RGBA2GRAY); 
     detector.detect(rgba, keyPoints); 

     // Save to database 
     MatchingDatabaseAdapter.addKeypoints(keyPoints, getApplicationContext()); 

     // Opens database cursor 
     MatchingDatabaseAdapter.getAllRecordsCursor(getApplicationContext()); 

     // Gets the first item in the database (as an example... you could loop through many/all) 
     MatOfKeyPoint keyPointsFromDb = MatchingDatabaseAdapter.getKeypointsFromNextCursorPosition(); 

     // Closes database 
     MatchingDatabaseAdapter.closeDb(); 

     Features2d.drawKeypoints(rgba, keyPointsFromDb, rgba); 
     Utils.matToBitmap(rgba, inputImage); 
     imageView.setImageBitmap(inputImage); 

    } 
} 

Вот код базы данных, который содержит некоторые сведения, связанные с преобразованием в массив байтов, необходимый для базы данных. Я не включил все, что связано с использованием базы данных, поскольку это действительно другая тема.

public class MatchingDatabaseAdapter { 
    ... 
    ... 
    ... 

    public static void addKeypoints(MatOfKeyPoint keyPoints, Context context) { 
     float[] data = new float[(int)keyPoints.total() * keyPoints.channels()]; // make a spot to save the data 
     keyPoints.get(0,0,data); // load the data; 
     ByteBuffer buffer = ByteBuffer.allocate(data.length * 4); 
     for (int i = 0; i < data.length; i++){ 
      buffer.putFloat(data[i]); 
     } 
     byte[] byteArray = buffer.array(); 
     addBlob(byteArray, keyPoints.rows(), keyPoints.cols(), keyPoints.type(), context); 
    } 

    public static void addBlob(byte[] blob, int rows, int columns, int mattype, Context context) throws SQLException { 
     if (mDb == null) mDb = openDb(context); 
     ContentValues contentValues = new ContentValues(); 
     contentValues.put(DatabaseHelper.BLOB_FIELD_NAME, blob); 
     contentValues.put(DatabaseHelper.ROWS_FIELD_NAME, rows); 
     contentValues.put(DatabaseHelper.COLUMNS_FIELD_NAME, columns); 
     contentValues.put(DatabaseHelper.MATTYPE_FIELD_NAME, mattype); 
     long x = mDb.insert(DatabaseHelper.TABLE_NAME, null, contentValues); 
     Log.v(TAG, "insert said " + x + " and blob was " + blob.length + " long."); 
     closeDb(); 
    } 

    public static Cursor getAllRecordsCursor(Context context) { 
     if (mDb == null || !mDb.isOpen()) mDb = openDb(context); 
     mCursor = mDb.query(DatabaseHelper.TABLE_NAME, null, null, null, null,null, null); 
     boolean hasRecords = mCursor.moveToFirst(); 
     Log.v(TAG, "MatchingDatabaseAdapter.getAllRecordsCursor() cursor created. " + mCursor + " and " + (hasRecords?"has records":"has NO RECORDS")); 
     return mCursor; 
    } 

    public static MatOfKeyPoint getKeypointsFromNextCursorPosition() { 
     MatOfKeyPoint keyPoints = null; 
     if (mCursor != null) { 
      Log.v(TAG, "mCursor has " + mCursor.getCount()); 
      mCursor.moveToFirst(); 
      int rows = mCursor.getInt(DatabaseHelper.ROWS_FIELD_POSITION); 
      int columns = mCursor.getInt(DatabaseHelper.COLUMNS_FIELD_POSITION); 
      int mattype = mCursor.getInt(DatabaseHelper.MATTYPE_FIELD_POSITION); 
      keyPoints = new MatOfKeyPoint(); 
      keyPoints.create(rows, columns, mattype); 
      byte[] blob = mCursor.getBlob(DatabaseHelper.BLOB_FIELD_POSITION); 
      ByteBuffer buffer = ByteBuffer.wrap(blob); 
      FloatBuffer floatBuffer = buffer.asFloatBuffer(); 
      float[] floatArray = new float[floatBuffer.limit()]; 
      floatBuffer.get(floatArray); 
      keyPoints.put(0, 0, floatArray); 
     } 
     return keyPoints; 
    } 

    // INNER CLASS DatabaseHelper 
    static class DatabaseHelper extends SQLiteOpenHelper { 
     private static DatabaseHelper mDatabaseHelper; 
     private static final String DB_NAME = "blobDb"; 
     private static final String TABLE_NAME = "blobTable"; 
     private static final String ROWS_FIELD_NAME = "rowsField"; 
     public static final int ROWS_FIELD_POSITION = 1; 
     private static final String COLUMNS_FIELD_NAME = "columnsField"; 
     public static final int COLUMNS_FIELD_POSITION = 2; 
     private static final String MATTYPE_FIELD_NAME = "mattypeField"; 
     public static final int MATTYPE_FIELD_POSITION = 3; 
     private static final String BLOB_FIELD_NAME = "blobField"; 
     private static final int BLOB_FIELD_POSITION = 4; 

     private static final java.lang.String CREATE_TABLE_SQL = 
       "CREATE TABLE " + TABLE_NAME + " (" 
         + "_id INTEGER PRIMARY KEY AUTOINCREMENT, " 
         + ROWS_FIELD_NAME + " INTEGER, " 
         + COLUMNS_FIELD_NAME + " INTEGER, " 
         + MATTYPE_FIELD_NAME + " INTEGER, " 
         + BLOB_FIELD_NAME + " BLOB" 
         + ");"; 

     private DatabaseHelper(Context context) { 
      super(context, DB_NAME, null, DB_VERSION); 
      mDatabaseHelper = this; 
     } 

     static synchronized DatabaseHelper getInstance(Context context) { 
      if (mDatabaseHelper == null) { 
       mDatabaseHelper = new DatabaseHelper(context.getApplicationContext()); 
      } 
      return mDatabaseHelper; 
     } 

     @Override 
     public void onCreate(SQLiteDatabase db) { 
      Log.v(TAG, "Creating table: " + CREATE_TABLE_SQL); 
      db.execSQL(CREATE_TABLE_SQL); 
     } 

     @Override 
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
      Log.v(TAG, "onUpgrade() from " + oldVersion + " to " + newVersion); 
      Log.v(TAG, "ALL DATA BEING REMOVED FROM THE DATABASE!!"); 
      db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME + ";"); 
      onCreate(db); 
     } 
    } 
} 

Полный образец работает проект и отображает прибой ключевые моменты, так что если вы хотите сохранить ключевые точки в базе данных, этот код должен получить, где вы хотите пойти.