虽然我没有运行计时,但我怀疑通过 XML 或 JSON 等格式将需要比使用原语更多的空间和计算资源。
下面是一些可用于在 Android 环境中将 MatOfKeyPoint 保存和检索到 SQLite 数据库的代码。这是使用 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);
}
}
}
完整的示例项目运行并显示 surf 关键点,因此如果您想将关键点保存到数据库,此代码应该可以让您到达您想去的地方。