Я разрабатываю мобильное приложение, которое работает на Android и IOS. Он способен обрабатывать видеопоток в реальном времени. На Android я получаю предварительный просмотр видеопотока камеры через android.hardware.Camera.PreviewCallback.onPreviewFrame. Я решил использовать формат NV21, поскольку он должен поддерживаться всеми Android-устройствами, а RGB — нет (или только RGB565).
Для моих алгоритмов, которые в основном предназначены для распознавания образов, мне нужны изображения в градациях серого, а также информация о цвете. Оттенки серого не проблема, но преобразование цвета из NV21 в BGR занимает слишком много времени.
Как описано, я использую следующий метод для захвата изображений;
В приложении я переопределяю onPreviewFrame-Handler камеры. Это делается в 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-объектов в виде локальных ссылок. Затем он преобразуется в поток байтов char* без знака и вызывает следующую функцию 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. Это то, что я уже сделал;
- Принят код «convertYUV420_NV21toRGB8888» в C++, предоставленный в этой теме (кратное времени конверсии)
- Изменен код с 1, чтобы использовать только целочисленные операции (удвоенное время преобразования openCV-Solution)
- Просмотрел пару других реализаций, все с аналогичным временем конверсии.
- Проверено OpenCV-Implementation, они используют много битового сдвига для повышения производительности. Думаю, я не могу сделать лучше сам
У вас есть предложения/знаете хорошие реализации или даже есть совершенно другой способ обойти эту проблему? Мне как-то нужно захватить RGB/BGR-кадры с Android-камеры, и это должно работать на как можно большем количестве Android-устройств.
Спасибо за ваши ответы!