在安卓平台上使用JNI进行图像解码和处理

9

背景

在一些应用中,处理大图像而不出现OOM并且快速是非常重要的。

为此,JNI(或renderscript,可惜缺乏文档)可能是一个不错的解决方案。

过去,我已经成功地使用JNI旋转巨大的位图,同时避免OOM(链接hereherehere)。这是一个不错的(但令人恼火的困难)经验,但最终它起作用了。

问题

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

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

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

我希望能够在JNI上执行所有图像操作(包括解码),以便在处理大型图像时不必担心OOM,并在过程结束时将数据转换为Java位图(以显示给用户)和/或写入文件。

再次强调,我不想将JNI侧的数据转换为Java位图,只是为了能够运行这些操作。

事实证明,有一些库提供许多函数(如JavaCV),但它们相当庞大,我不太确定它们的功能以及它们是否真的在JNI端执行解码,因此我更喜欢知道Android内置JNI函数可以做什么。

问题

在Android的JNI侧可用哪些函数进行图像操作?

例如,我如何在位图上运行面部检测,应用矩阵,降低位图分辨率,缩放位图等等...?

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

即使我自己实现这些操作,也可能有其他人通过C / C ++进行了更有效的实现,考虑到C / C ++可以进行许多优化。

当我转向Android的JNI侧时,需要从头开始实现所有内容吗?

只是为了澄清,我感兴趣的是:

在Java中输入位图 -> 纯JNI和C / C ++中的图像处理(完全不转换为Java对象) -> 在Java输出位图。


1
我已经了解了安卓所提供的内容。此外,根据我的阅读,这个库要求最终用户自己将其库安装为应用程序:https://play.google.com/store/apps/details?id=org.opencv.engine。我不确定为什么会这样(库的大小?),但要求用户安装另一个应用程序可能很烦人。我听说这个库在资源方面太“沉重”,即使在我的Galaxy S3设备上,当我尝试从Sony的示例应用程序中使用它时也是如此:http://developer.sonymobile.com/knowledge-base/tutorials/android_tutorial/get-started-with-opencv-on-android/。 - android developer
OpenCV 可在 BSD 风格许可下使用,因此可以复制/粘贴您需要的部分... 无论如何,如果您的问题是关于使用 Android 功能的,答案显然是肯定的:我们可以通过 JNI 使用所有功能。 如果您想要高效的东西,那就是另外一个问题。 您需要澄清您的优先事项。 - Samuel Audet
你可以随意使用它,只需保留许可证文档并不提及他们的名称。很好。无论如何,我从未使用过这个库,而且我认为从中“剖解”出我需要的东西相当复杂。关于Android中的JNI,我知道我可以实现所有东西,问题是Android有什么可以帮助我。例如,在Java端,我们有面部检测。在JNI端是否也有同样的功能?如果Android在JNI上拥有与Java上相同的基本功能,我认为我会更喜欢使用它而不是“剖解”其他库。 - android developer
当然,我们可以通过JNI访问所有内容。 - Samuel Audet
我们有[FaceDetector]类(http://developer.android.com/reference/android/media/FaceDetector.html),因此我们可以使用[NewObject](http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp4517)创建一个实例。我想你能想出剩下的部分吧? - Samuel Audet
显示剩余7条评论
2个回答

5
“Android 内置的 JNI 函数”有点自相矛盾。从技术上讲,许多 Android 框架 Java 类在某个地方使用 JNI 调用本地库是正确的。但是,关于这个说法有三个保留意见。
1. 这些都是“实现细节”,可能会在 Android 的下一个版本、任何分支(例如 Kindle)或甚至 OEM 版本中(不被视为“分支”,例如由 Samsung 构建或针对 Quallcom SOC 构建)没有通知地进行更改。 2. 核心 Java 类中本地方法的实现方式与“传统”的 JNI 不同。这些方法被 JVM 预加载和缓存,因此不会遭受大部分 JNI 调用典型开销的影响。 3. 没有什么可以让你的 Java 或本地代码直接与其他类的 JNI 方法交互,特别是构成系统框架的类。

所有这些都说了,你可以自由地研究Android的源代码,找到支持特定类和方法(例如面部检测)的本机库,并在本机代码中使用这些库,或者构建自己的JNI层以从Java代码中使用这些库。


为了举个具体的例子,在Android中,人脸检测是通过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 编解码器是一个特殊的存在。在现代系统中(我记得自 2.2 版本以来),你可以期望 /system/lib/libjpeg.so 存在。但是许多平台也有更高效的 Jpeg 编解码器的硬件实现,通过使用 libstagefright.so 或 OpenMAX,并且通常在 android.graphics.Bitmap.compress()android.graphics.BitmapFactory.decode***() 方法中使用这些实现。

还有一种优化的 libjpeg-turbo,它比 /system/lib/libjpeg.so 有其独特的优势。


@androiddeveloper:“那么没有官方的方法可以在C/C++上解码图像(例如)吗?只能通过Java来做吗?” -- 你可以使用一个库来在这些语言中(或几乎任何其他编程语言中)解码图像。这个库的来源可能会有所不同。“所以谷歌说它支持两种语言的整个想法并不完全正确”-- “支持”并不意味着“完全相同的支持”。请阅读NDK文档 - CommonsWare
NDK 包含许多子系统,其中之一是本地位图 API。它受 Froyo(2.2)及更高版本的 Android 支持。作为官方支持,保证在所有设备上都可以正常运行。 - Alex Cohn
@AlexCohn 它只能获取已解码位图的信息,锁定和解锁它。它无法以任何可能的方式解码位图。我已经写过我使用了 NDK 并使用了这些函数,但我正在寻找的不仅仅是这些... - android developer
@CommonsWare 那么,如果我仍然希望在C/C++上解码位图,下一步该怎么做呢?从Android源代码复制会有帮助吗?它能在所有Android设备上工作吗?您是否知道任何极简、免费的第三方库,应该能够很好地完成这个任务? - android developer
虽然你没有问我,但我建议使用libjpeg-turbo,并使用一个包装器来重用本地Android代码以生成与位图兼容的格式。 - Alex Cohn
显示剩余12条评论

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接