对于 Android 项目,我必须实时分析相机帧。现在我使用“android.hardware.Camera.PreviewCallback”来接收相机帧。问题是,当我尝试分析帧时,我的 FPS 从 30 fps 下降到 15 fps,而我需要 30 fps。我已经尝试在单独的线程中处理分析部分,帧停止下降,但分析不再是实时的。
有人有解决这个问题的方法吗?
对于 Android 项目,我必须实时分析相机帧。现在我使用“android.hardware.Camera.PreviewCallback”来接收相机帧。问题是,当我尝试分析帧时,我的 FPS 从 30 fps 下降到 15 fps,而我需要 30 fps。我已经尝试在单独的线程中处理分析部分,帧停止下降,但分析不再是实时的。
有人有解决这个问题的方法吗?
可能的选项:
请记住,那里有很多慢速设备。帧率还取决于光照情况。因此,如果您想发布您的应用程序,请确保您的应用程序也能够支持较低的帧速率。
正如@oberflansch 所提到的,可能有多种方法可以解决您的问题。
如果您必须进行 YUV 到 RGB 的转换,这并不便宜,以及其他分析,RenderScript 可能是您的出路。它具有快速的YuvToRGB 转换内在特性,并且可能为您的分析带来巨大的性能提升。
这是一个使用带有相机的 RenderScript 的示例:https ://github.com/googlesamples/android-HdrViewfinder
您也可以尝试像上面的示例一样在 YUV 空间中进行分析,这将帮助您摆脱 YUVtoRGB 转换的成本。
但是如果你需要在 RGB 空间中进行,ScriptIntrinsicYuvToRGB 使用起来很简单:
// Setup the Allocations and ScriptIntrinsicYuvToRGB.
// Make sure you reuse them to avoid overhead.
Type.Builder yuvTypeBuilder = new Type.Builder(rs, Element.YUV(rs));
yuvTypeBuilder.setX(dimX).setY(dimX).setYuvFormat(ImageFormat.YUV_420_888);
// USAGE_IO_INPUT is used with Camera API to get the image buffer
// from camera stream without any copy. Detailed usage please
// refer to the example.
mInputAllocation = Allocation.createTyped(rs, yuvTypeBuilder.create(),
Allocation.USAGE_IO_INPUT | Allocation.USAGE_SCRIPT);
Type.Builder rgbTypeBuilder = new Type.Builder(rs, Element.RGBA_8888(rs));
rgbTypeBuilder.setX(dimX).setY(dimY);
// USAGE_IO_OUTPUT can be used with Surface API to display the
// image to the surface without any copy.
// You can remove it if you don't need to display the image.
mOutputAllocation = Allocation.createTyped(rs, rgbTypeBuilder.create(),
Allocation.USAGE_IO_OUTPUT | Allocation.USAGE_SCRIPT);
ScriptIntrinsicYuvToRGB yuvToRgb = ScriptIntrinsicYuvToRGB.create(rs, Element.RGBA_8888(rs));
.........
// Each time on a new frame available, do the process.
// Please refer to the example for details.
mInputAllocation.ioReceive();
// YUV to RGB conversion
yuvToRgb.setInput(mInputAllocation);
yuvToRgb.forEach(mOutputAllocation);
// Do the analysis on the RGB data, using mOutputAllocation.
..........
因为我必须分析 RGB 和 HSV 值,所以我不能使用@Settembrini 提到的解决方案。为了解决我的问题,我使用 Android NDK 在 C 中创建了一个函数。C 函数处理分析并返回结果。即使在速度较慢的设备上,我也能达到我需要的 30 FPS。在大多数情况下,@Miao Wang 的解决方案可能会成立。
对于 Android Studio 用户:
在您的活动中集成本机方法:
// loading native c module/lib
static {
try {
System.loadLibrary("rgbhsvc");
} catch (UnsatisfiedLinkError ule) {
Log.e(DEBUG_TAG, "WARNING: Could not load native library: " + ule.getMessage());
}
}
//Create native void to calculate the RGB HSV
private native void YUVtoRBGHSV(double[] rgb_hsv, byte[] yuv, int width, int height);
创建 C 部分来处理数据:
JNIEXPORT
void
JNICALL Java_nl_example_project_classes_Camera_YUVtoRBGHSV(JNIEnv * env, jobject obj, jdoubleArray rgb_hsv, jbyteArray yuv420sp, jint width, jint height)
{
// process data
(*env)->SetDoubleArrayRegion(env, rgb_hsv, 0, sz, ( jdouble * ) &rgbData[0] );
//Release the array data
(*env)->ReleaseByteArrayElements(env, yuv420sp, yuv, JNI_ABORT);
}
Android NDK 的一个很好的介绍:https ://www.sitepoint.com/using-c-and-c-code-in-an-android-app-with-the-ndk/
感谢所有的答案!
除了上面所说的,如果你的图像分析可以单独使用灰度信息,你不需要任何初始转换为 RGB。如果您的分辨率为 n 乘以 m 像素,则只需从 YUV 数据中获取前 (n*m) 个字节。对于旧相机和 Camera2 都是如此。