Android Camera сбрасывает кадры от работы в PreviewCallback

Для проекта Android я должен анализировать кадры камеры в режиме реального времени. Теперь я использую android.hardware.Camera.PreviewCallback для получения кадров камеры. Проблема в том, что при попытке проанализировать кадры мой FPS падает с 30 кадров в секунду до 15 кадров в секунду, а мне нужно 30 кадров в секунду. Я уже пытался обработать анализирующую часть в отдельном потоке, кадры перестали падать, но анализ больше не выполнялся в реальном времени.

У кого-нибудь есть решение этой проблемы?

4 ответа

Возможные варианты:

  • снизить разрешение
  • оптимизировать свой алгоритм (или использовать другой)
  • проанализировать ваши кадры в с
  • если возможно, используйте шейдеры или, возможно, Renderscript
  • более чем 2 темы также могут помочь. (зависит от аппаратного обеспечения)

Имейте в виду, что есть много медленных устройств. Частота кадров также зависит от освещенности. Поэтому, если вы хотите опубликовать свое приложение, убедитесь, что оно также поддерживает более низкую частоту кадров.

Поскольку мне приходилось анализировать значения RGB и HSV, я не мог использовать упомянутое решение @Setmbrini. Чтобы решить мою проблему, я создал функцию в C, используя Android NDK. Функция C обрабатывает анализ и возвращает результат. Даже на более медленных устройствах я достигаю 30 FPS, которые мне нужны. Вероятно, в большинстве случаев решение @Miao Wang будет стоять.

Для пользователей Android-студии:

  • Установите NDK из SDK Tools (Файл> Параметры> Внешний вид и поведение> Настройки системы> Android SDK (вкладка Инструменты SDK).
  • Создайте подкаталог с именем "jni" и разместите здесь все нативные источники.
  • Создайте "Android.mk", чтобы описать ваши собственные исходные коды для системы сборки NDK.
  • Создайте свой собственный код, запустив скрипт "ndk-build" (в каталоге, установленном NDK) из каталога вашего проекта. Инструменты сборки копируют разделенные, совместно используемые библиотеки, необходимые вашему приложению, в нужное место в каталоге проекта приложения.

Интегрируйте нативный метод в свою деятельность:

// 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/

Спасибо за ответы на все вопросы!

Может быть несколько способов решить вашу проблему, как упомянуто @oberflansch.

Если вам нужно выполнить конвертацию YUV в RGB, что недешево, как и другие анализы, RenderScript может стать вашим выходом. Он имеет быстрое преобразование YuvToRGB и потенциально может значительно повысить производительность вашего анализа.

Вот пример использования RenderScript с камерой: https://github.com/googlesamples/android-HdrViewfinder

Вы также можете попробовать выполнить анализ в пространстве YUV, как показано в примере выше, что поможет вам избавиться от стоимости преобразования YUV to RGB.

Но если вам нужно сделать это в пространстве 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.
    ..........

В дополнение к тому, что было сказано выше, если ваш анализ изображений может работать только с информацией Grayvalue, вам не нужно никакого первоначального преобразования в RGB. Если у вас есть разрешение в n раз m пикселей, вы можете взять первые (n*m) байты из данных YUV. Это верно как для старой камеры, так и для камеры2.

Другие вопросы по тегам