android — преобразование YUV (NV21) в BGR на мобильных устройствах (собственный код)

Я разрабатываю мобильное приложение, которое работает на Android и IOS. Он способен в реальном времени обрабатывать видеопоток. На Android я получаю Preview-Videostream камеры через android.hardware.Camera.PreviewCallback.onPreviewFrame. Я решил использовать NV21-формат, поскольку он должен поддерживаться всеми Android-устройствами, тогда как RGB — нет (или только RGB565).

Для моих алгоритмов, которые в основном предназначены для распознавания образов, мне нужны изображения в градациях серого, а также информация о цвете. Оттенки серого не проблема, но преобразование цвета из NV21 в BGR занимает слишком много времени.

Как описано, я использую следующий метод для захвата изображений;

В приложении я переопределяю обработчик onPreviewFrame камеры. Это делается в CameraPreviewFrameHandler.java:

 @Override
public void onPreviewFrame(byte[] data, Camera camera) {
{
try {
AvCore.getInstance().onFrame(data, _prevWidth, _prevHeight, AvStreamEncoding.NV21);
} catch (NativeException e)
{
e.printStackTrace();
}
}

Затем onFrame-Function вызывает встроенную функцию, которая извлекает данные из Java-объектов в качестве локальных ссылок. Затем он преобразуется в unsigned char * bytestream и вызывает следующую функцию c ++, которая использует OpenCV для преобразования из NV21 в BGR:

void CoreManager::api_onFrame(unsigned char* rImageData, avStreamEncoding_t vImageFormat, int vWidth, int vHeight)
{
// rImageData is a local JNI-reference to the java-byte-array "data" from onPreviewFrame
Mat bgrMat; // Holds the converted image
Mat origImg;    // Holds the original image (OpenCV-Wrapping around rImageData)

double ts; // for profiling
switch(vImageFormat)
{
// other formats
case NV21:
origImg = Mat(vHeight + vHeight/2, vWidth, CV_8UC1, rImageData); // fast, only creates header around rImageData
bgrMat = Mat(vHeight, vWidth, CV_8UC3); // Prepare Mat for target image
ts = avUtils::gettime();                // PROFILING START
cvtColor(origImg, bgrMat, CV_YUV2BGRA_NV21);
_onFrameBGRConversion.push_back(avUtils::gettime()-ts); // PROFILING END
break;
}

[...APPLICATION LOGIC...]
}

Как можно заключить из комментариев в коде, я уже профилировал преобразование, и оказалось, что на моем Nexus 4 требуется ~ 30 мс, что недопустимо долго для такого «тривиального» этапа предварительной обработки. (Мои методы профилирования перепроверены и работают правильно для измерения в реальном времени)

Сейчас я отчаянно пытаюсь найти более быструю реализацию этого преобразования цвета из NV21 в BGR. Это то, что я уже сделал;

  1. Принят код «convertYUV420_NV21toRGB8888» для C ++ при условии в этой теме (кратно времени преобразования)
  2. Изменен код с 1 для использования только целочисленных операций (удвоенное время преобразования openCV-Solution)
  3. Просматривал пару других реализаций, все с похожим временем конверсии
  4. Проверил OpenCV-реализацию, они используют много сдвигов для получения производительности. Думаю, я не могу сделать лучше самостоятельно

У вас есть предложения / знаете хорошие реализации или у вас есть совершенно другой способ обойти эту проблему? Мне как-то нужно захватывать RGB / BGR-кадры с Android-камеры, и она должна работать на максимально возможном количестве Android-устройств.

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

0

Решение

Ты пробовал либьюв? Я использовал его в прошлом, и если вы компилируете его с поддержкой NEON, он использует код asm, оптимизированный для процессоров ARM, вы можете начать с него для дальнейшей оптимизации для вашей особой ситуации.

1

Другие решения

Других решений пока нет …