8

背景

在某些应用程序中,重要的是要在没有 OOM 的情况下快速处理大图像。

为此,JNI(或渲染脚本,遗憾的是缺乏文档)可能是一个不错的解决方案。

过去,我成功地使用 JNI 来旋转巨大的位图,同时避免 OOM(链接在这里这里这里)。这是一个很好的(但令人讨厌的)体验,但最终它奏效了。

问题

android框架有很多函数来处理位图,但我不知道JNI方面的情况如何。

我已经知道如何将位图从 android 的“java 世界”传递到“JNI 世界”并返回。

我不知道我可以在 JNI 端使用哪些函数来帮助我处理位图。

我希望能够在 JNI 上进行所有图像操作(包括解码),这样在呈现大图像时我就不必担心 OOM,并且在过程结束时,我可以将数据转换为 Java-位图(向用户显示)和/或将其写入文件。

同样,我不想将 JNI 端的数据转换为 java 位图,只是为了能够运行这些操作。

事实证明,有一些库提供了许多功能(如JavaCV),但它们非常大,我不太确定它们的功能以及它们是否真的在 JNI 端进行解码,所以我更喜欢而是能够通过Android的内置JNI功能知道什么是可能的。

问题

哪些函数可用于 Android 上 JNI 端的图像处理?

例如,我如何在位图上运行人脸检测、应用矩阵、下采样位图、缩放位图等等......?

对于一些操作,我已经可以想出一种方法来实现它们(缩放图像很容易,维基百科可以提供很多帮助),但有些非常复杂。

即使我自己实现了这些操作,也许其他人已经提高了它的效率,因为考虑到 C/C++ 可以有这么多的优化。

当我去 android 的 JNI 端时,我真的是靠我自己吗,我需要从头开始实现一切?

为了清楚起见,我感兴趣的是:

java 上的输入位图-> 纯粹在 JNI 和 C/C++ 中进行图像处理(不转换为 java 对象)-> java 上的输出位图。

4

2 回答 2

5

“Android 的内置 JNI 功能”有点矛盾。从技术上讲,许多 Android 框架 Java 类在链的某个位置使用 JNI 来调用本机库是正确的。

但对这一说法有三处保留。

  1. 这些是“实施细节”,可能会在任何下一版本的 Android 或任何分叉(例如 Kindle),甚至不被视为“分叉”的 OEM 版本(例如由三星制造或为 Quallcom 构建)中更改,恕不另行通知SOC)。

  2. 在核心 Java 类中实现本机方法的方式与“经典”JNI 不同。这些方法由 JVM 预加载和缓存,因此不会受到 JNI 调用的大部分典型开销的影响。

  3. 您的 Java 或本机代码无法直接与其他类的 JNI 方法交互,尤其是构成系统框架的类。

综上所述,您可以自由研究Android 的源代码,找到支持特定类和方法(例如人脸检测)的本地库,并在您的本地代码中使用这些库,或者构建自己的 JNI 层从您的 Java 代码中使用这些库。


举个具体的例子,A ​​ndroid 中的人脸检测是通过android.media.FaceDetector类实现的,该类加载libFFTEm.so. 您可以查看本机代码,并根据需要使用它。你不应该假设它libFFTEm.so会出现在设备上,或者设备上的库将具有相同的 API。

但在这种特定情况下,这不是问题,因为所有工作neven都是完全基于软件的。因此,您可以完全复制此代码,也可以只复制其中的相关部分,并将其作为您的本地库的一部分。请注意,对于许多设备,您可以简单地加载和使用/system/lib/libFFTEm.so并且永远不会感到不适,直到您遇到一个行为不端的系统。

通过阅读本机代码可以得出一个值得注意的结论,即底层算法忽略了颜色信息。因此,如果要查找人脸坐标的图像来自 YUV 源,则调用时可以避免很多开销

// run detection
btk_DCR_assignGrayByteImage(hdcr, bwbuffer, width, height);

int numberOfFaces = 0;
if (btk_FaceFinder_putDCR(hfd, hdcr) == btk_STATUS_OK) {
    numberOfFaces = btk_FaceFinder_faces(hfd);
} else {
    ALOGE("ERROR: Return 0 faces because error exists in btk_FaceFinder_putDCR.\n");
}

直接使用您的 YUV(或 Y)字节数组,而不是在android.media.FaceDetector.findFaces()中将其转换为 RGB 并返回到 YUV 。如果您的 YUV 缓冲区来自 Java,您可以构建自己的类YuvFaceDetector,该类将是android.media.FaceDetector的副本,唯一的区别是仅YuvFaceDetector.findFaces()采用 Y(亮度)值而不是位图,并避免 RGB 到 Y 的转换.


其他一些情况并不像这样容易。例如,视频编解码器与硬件平台紧密耦合,您不能简单地将代码从libstagefright.so复制到您的项目中。Jpeg 编解码器是一种特殊的野兽。在现代系统(IIRC,自 2.2 起)中,您可以期望/system/lib/libjpeg.so在场。但是许多平台也通过或 OpenMAX 有更高效的 Jpeg 编解码器硬件实现libstagefright.so,并且这些通常用于android.graphics.Bitmap.compress()android.graphics.BitmapFactory.decode***()方法。

还有一个优化的libjpeg-turbo,它比/system/lib/libjpeg.so.

于 2014-02-06T11:05:29.837 回答
1

您的问题似乎更多地是关于 C/C++ 图像处理库,而不是关于 Android 本身。为此,这里有一些其他 StackOverflow 问题可能包含您认为有用的信息:

快速跨平台 C/C++ 图像处理库

C++ 图像处理库

于 2014-02-10T23:09:00.637 回答