Android中Java使用OpenCV ReadNet读取Assets输入流问题
问题
我需要调用OpenCV的readNetFromDarknet函数,但模型文件(yolov4-tiny.cfg和yolov4-tiny.weights)来自Android项目的Assets目录,目前只能通过InputStream获取这些文件,无法直接传入readNetFromDarknet。已经成功解析了Assets中的coco.names类名,但不知道该如何正确调用这个函数——能不能直接用Assets的路径?还是必须先把Assets里的文件导出到安卓设备本地再调用?
当前代码:
public DNN(Context m_context){ AssetManager assetManager = m_context.getAssets(); try { InputStream ims1 = assetManager.open("coco.names"); InputStream ims2 = assetManager.open("yolov4-tiny.cfg"); InputStream ims3 = assetManager.open("yolov4-tiny.weights"); classes = new BufferedReader(new InputStreamReader(ims1, StandardCharsets.UTF_8)).lines().collect(Collectors.toList()); } catch(IOException e) { e.printStackTrace(); } net = Dnn.readNetFromDarknet("yolov4-tiny.cfg", "yolov4-tiny.weights"); }
解决方案
核心结论
OpenCV的readNetFromDarknet函数不支持直接传入InputStream,也无法直接使用Assets目录的路径(Assets是APK内的压缩资源,没有系统可直接访问的文件路径)。必须先将Assets中的.cfg和.weights文件复制到安卓设备的本地存储(比如内部缓存目录),再用本地文件路径调用函数。
具体实现步骤
- 添加文件复制工具方法
写一个通用方法,将Assets中的文件复制到本地指定路径:
private void copyAssetToLocal(Context context, String assetFileName, String destFilePath) throws IOException { AssetManager assetManager = context.getAssets(); try (InputStream in = assetManager.open(assetFileName); OutputStream out = new FileOutputStream(destFilePath)) { byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) != -1) { out.write(buffer, 0, read); } } }
- 修改DNN类构造方法
在初始化网络前,先把模型文件复制到本地缓存目录,再用本地路径加载:
public DNN(Context m_context){ AssetManager assetManager = m_context.getAssets(); File cacheDir = m_context.getCacheDir(); String cfgLocalPath = new File(cacheDir, "yolov4-tiny.cfg").getAbsolutePath(); String weightsLocalPath = new File(cacheDir, "yolov4-tiny.weights").getAbsolutePath(); try { // 解析coco.names类名 InputStream ims1 = assetManager.open("coco.names"); classes = new BufferedReader(new InputStreamReader(ims1, StandardCharsets.UTF_8)).lines().collect(Collectors.toList()); // 复制模型文件到本地缓存 copyAssetToLocal(m_context, "yolov4-tiny.cfg", cfgLocalPath); copyAssetToLocal(m_context, "yolov4-tiny.weights", weightsLocalPath); } catch(IOException e) { e.printStackTrace(); } // 使用本地路径加载网络 net = Dnn.readNetFromDarknet(cfgLocalPath, weightsLocalPath); }
优化建议
可以添加文件存在判断,避免每次初始化都重复复制文件,提升性能:
File cfgFile = new File(cacheDir, "yolov4-tiny.cfg"); if (!cfgFile.exists()) { copyAssetToLocal(m_context, "yolov4-tiny.cfg", cfgLocalPath); } File weightsFile = new File(cacheDir, "yolov4-tiny.weights"); if (!weightsFile.exists()) { copyAssetToLocal(m_context, "yolov4-tiny.weights", weightsLocalPath); }
内容的提问来源于stack exchange,提问作者Mich
相关产品推荐
相关产品推荐

