8

我有一个训练图像集,我已经检测计算了每个图像的特征向量(使用 ORB 特征描述符和提取器。问题是:因为我需要保存这些特征以重新利用它们与测试图像匹配(使用SVM 分类器);在 Android 设备上本地存储特征向量的最佳方式是什么?

每个图像要保存的特征向量的大小是可变的,因此那些具有非最大大小的特征向量用零填充以统一所有向量的大小。当前最大尺寸为 500 行 x 32 列;因此有 16k 个特征。

这是我到目前为止可以达到的选项;

  • 我听说过 OpenCV 的FileStorage,但是在浏览 java 文档时,我注意到了save一种用于HOG 功能(不是 ORB)的方法。此外,鉴于 xml 文件太大而无法加载,我不确定使用 OpenCV 的文件存储选项保存功能是否是 Android 手机的最佳内存方式。
  • 我目前的选择是选择一个 sqlLite 数据库,它有一个包含两个列的表;id 和 feature(经常在网上建议);将 sqlLite 中的所有 16k 功能制成表格。这似乎是手机存储密集型的,但这是我能找到的最合理的解决方案。

有没有一种通用的方法来处理 Android 手机上的特征向量?是否包含上述任何一种方法;如果不能,您能否就如何实施这种存储解决方案提供一些指导?

谢谢你。

4

3 回答 3

5

在我看来,最通用的存储关键点的方法是首先将它们转换为像 JSON 这样的数据交换格式。

在您能够进行该转换后,您可以灵活地存储它。JSON 很容易转换为字符串和/或通过网络连接发送。

使用 OpenCV C++ ,您可以将数据存储为 YAML,但这不适用于 Android。

要在 Java 中解析 JSON,您可以使用这个易于使用的库 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;
}
于 2014-02-21T00:39:37.393 回答
0

我建议将特征向量存储为图像,以获得简单而紧凑的表示。您甚至可以使用非破坏性压缩(例如 png)来最小化文件大小。

于 2013-12-31T12:43:14.873 回答
0

我看到您已经考虑使用 Android SQLite 数据库:

我目前的选择是选择一个 sqlLite 数据库,它有一个包含两个列的表;id 和 feature(经常在网上建议);将 sqlLite 中的所有 16k 功能制成表格。这似乎是手机存储密集型的,但这是我能找到的最合理的解决方案。

一种MatOfKeyPoint方法可以以合理的效率 保存和检索到 SQLite 数据库。

使用数据库的优点是不需要向用户请求写入外部存储权限(尽管您的某些其他应用程序功能可能需要该权限)。

有一个完整的 Android 解决方案,Java 代码可以在这个 StackOverflow Answer中找到。

以下是对该答案的代码中发生的事情的描述......

MatOfKeyPoint 到 byte[] 和一些属性

要保存到数据库,您需要保存到byte[]对象。使用该MatOfKeyPoint.get()方法,您可以获得填充的float[]. 然后使用ByteBuffer.putFloat(),您可以遍历所有的浮点数,最后byte[]使用ByteBuffer.array().

您还需要将一些属性MatOfKeyPoint.rows()MatOfKeyPoint.cols()MatOfKeyPoint.type()与 的 一起保存到您的数据库blobbyte[]

数据库 blob (byte[]) 到 MatOfKeyPoint

要从数据库中重构MatOfKeyPoint对象,首先要从float[]blob 中创建一个。使用ByteBuffer.wrap(blob),然后运行ByteBuffer.asFloatBuffer(),最后FloatBuffer.get()使用大小合适的新float[].

现在你已经yourFloatArray运行了MatOfKeyPoint.create(rows, cols, type),这三件事来自数据库记录。最后你跑了MatOfKeyPoint.put(0, 0, yourFloatArray)

于 2017-05-23T14:38:19.593 回答