使用OpenCV4Android保存ORB特征向量(java API)

时间:2013-03-07 12:35:56

标签: android opencv vector storage feature-detection

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

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

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

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

在Android手机上有处理特征向量的常用方法吗?它是否包含上述任何方法;如果没有,请您提供一些有关如何实施此类存储解决方案的指南?

谢谢。

3 个答案:

答案 0 :(得分:5)

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

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

使用OpenCV C ++ you are able to store data as YAML,但尚未适用于Android。

要解析Java中的JSON,您可以使用这个易于使用的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;
}

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

  

我目前的选择是选择一个sqlLite数据库,有一个包含两个cols的表; id和功能(如在线经常建议的那样);列表sqlLite中的所有16k功能。这似乎是电话存储密集型,但它是我能找到的最合理的解决方案。

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

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

有一个完整的Android解决方案,其中包含可在this StackOverflow Answer中找到的Java代码。

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

MatOfKeyPoint到byte []和一些属性

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

您还需要将一些attirbutes MatOfKeyPoint.rows()MatOfKeyPoint.cols()MatOfKeyPoint.type()blob的{​​{1}}一起保存到您的数据库中。

数据库blob(byte [])到MatOfKeyPoint

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

现在您运行float[] yourFloatArray,这三件事来自数据库记录。最后,您运行MatOfKeyPoint.create(rows, cols, type)