我有一组训练图像,每个图像都有detected和computed个特征向量(使用ORB特征描述符和提取器。问题 :因为我需要保存这些功能以重新使用它们以匹配测试图像(使用SVM分类器); 在Android设备上本地存储特征向量的最佳方法是什么?
要保存的特征向量是每个图像的可变大小,因此具有非最大大小的特征向量用零填充以统一所有向量的大小。目前最大尺寸为500行×32列;因此16k功能。
这是我到目前为止可以达到的选项;
save
方法(不是ORB)。此外,我不确定使用OpenCV的文件存储选项保存功能对于Android手机来说是否是最佳内存方式,因为xml文件太大而无法加载。在Android手机上有处理特征向量的常用方法吗?它是否包含上述任何方法;如果没有,请您提供一些有关如何实施此类存储解决方案的指南?
谢谢。
答案 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代码。
以下是该答案代码中发生的事情的描述......
要保存到数据库,您需要保存到byte[]
对象。使用MatOfKeyPoint.get()
方法,您可以获得已填充的float[]
。然后使用ByteBuffer.putFloat()
,您可以遍历所有浮点数,最后使用byte[]
获取已填充的ByteBuffer.array()
。
您还需要将一些attirbutes MatOfKeyPoint.rows()
,MatOfKeyPoint.cols()
和MatOfKeyPoint.type()
与blob
的{{1}}一起保存到您的数据库中。
要从数据库中重新构建byte[]
对象,首先要从blob中创建MatOfKeyPoint
。使用float[]
,然后使用适当大小的新ByteBuffer.wrap(blob)
运行ByteBuffer.asFloatBuffer()
,最后FloatBuffer.get()
。
现在您运行float[]
yourFloatArray
,这三件事来自数据库记录。最后,您运行MatOfKeyPoint.create(rows, cols, type)
。