¿Cómo guardar las características de Keypoint de OpenCV en la base de datos?

Mi proyecto es el reconocimiento de la hoja en Android usando OpenCV biblioteca. Estoy utilizando la detección de ORB para obtener el punto clave de la imagen y el uso de descriptor ORB para obtener la característica del punto clave. Este es el código que uso:

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); 

Fuente: http://answers.opencv.org/question/6260/orb-features/

Pero cada entrada i la misma imagen, el punto clave de esa imagen siempre diferente. ¿Puedo guardar la característica del punto clave en la base de datos si eso siempre es diferente? ¿O debo guardar la imagen para guardar los datos de la característica? Si eso puede ahorrar a la base de datos, ¿cómo puedo hacer eso?

En mi opinión, la forma más universal de almacenar los puntos clave es primero convertirlos a un formato de intercambio de datos como JSON.

Después de que usted pueda hacer esa conversión usted tiene mucha flexibilidad para almacenarla. JSON se convierte fácilmente en una cadena y / o se envía a través de una conexión de red.

Con OpenCV C ++ puede almacenar datos como YAML , pero eso no está disponible para Android todavía.

Para analizar JSON en Java puede utilizar esta biblioteca fácil de usar Google GSON .

Y aquí está mi primer intento de hacer exactamente eso:

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

Recientemente termino un proyecto sobre el reconocimiento del gesto humano. Pero he utilizado svm de openCv. Para su número de punto clave de información en cada imagen es su punto saliente (de acuerdo con la definición openCv). Para el reconocimiento o en otras palabras "predicción" debe guardar la característica del punto clave (Keypoint Property) que es un tapete. Utilicé SURF y calculo la característica 64 para cada punto clave. Espero que ayude.

Aunque no he ejecutado los tiempos, sospecho que pasar por formatos como XML o JSON requeriría más espacio y recursos computacionales que usar primitivos.

A continuación se muestra un código que se puede utilizar para guardar y recuperar MatOfKeyPoint a la base de datos SQLite en un entorno Android. Esto es usar OpenCV 2.4.11 para que SIFT esté disponible.

Lo que ve cuando ejecuta esta aplicación es su imagen de prueba (que debe suministrar y colocar en la carpeta dibujable) con claves adicionales.

El método siftTest() comienza calculando keyPoints que es el tipo MatOfKeyPoint . El código guarda los datos subyacentes de ese objeto en la base de datos, luego lee los datos y crea un nuevo objeto keyPointsFromDb , keyPointsFromDb contenido se aplica a la imagen original y se muestra el resultado.

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

Aquí está el código de la base de datos que contiene algunos detalles asociados con la conversión a la matriz de bytes requerida para la base de datos. No he incluido todo lo relacionado con el uso de una base de datos, ya que es realmente un tema diferente.

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

El proyecto completo de muestra se ejecuta y muestra los puntos clave de surf, por lo que si desea guardar los puntos clave en una base de datos, este código debe llevarlo a donde quiere ir.

  • System.LoadLibrary (libname) se estrella en el chipset Nvidia Tegra 2 (Android Samsung Tab) en código Javacv
  • ¿Cómo puedo usar OpenCV con imágenes almacenadas, sin una cámara?
  • Segmentación de imágenes por color de fondo - OpenCV Android
  • Obtener la longitud focal de la cámara OpenCV Android
  • Confusión entre los tipos de datos OpenCv4Android y C ++
  • Android no puede cargar la imagen orientada correcta desde la galería
  • OpenCV Android - edición de color usando CameraBridgeViewBase
  • Filtrado de MatOfDMatch
  • Uso de funciones nativas en Android con OpenCV
  • Android NDK. Ninguna sección de C / C ++ en las propiedades del proyecto de Eclipse
  • Programación Android Camera.PreviewCallback (con OpenGL y OpenCV)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.