Декодирование изображений и манипулирование с использованием JNI на Android
фон
В некоторых приложениях важно обрабатывать большие изображения без OOM, а также быстро.
Для этого JNI (или Renderscript, который, к сожалению, отсутствует в документации) может быть хорошим решением.
В прошлом мне удавалось использовать JNI для вращения огромных растровых изображений, избегая при этом OOM (ссылка здесь, здесь и здесь). это был хороший (но раздражающе сложный) опыт, но в итоге это сработало.
эта проблема
Платформа Android имеет множество функций для обработки растровых изображений, но я понятия не имею, какова ситуация на стороне JNI.
Я уже знаю, как передать растровое изображение из "мира Java" Android в "мир JNI" и обратно.
Что я не знаю, так это то, какие функции я могу использовать на стороне JNI, чтобы помочь мне с растровыми изображениями.
Я хотел бы иметь возможность выполнять все операции с изображениями (включая декодирование) на JNI, так что мне не нужно будет беспокоиться об OOM при представлении больших изображений, и в конце процесса я смог преобразовать данные в Java. растровое изображение (чтобы показать пользователю) и / или записать его в файл.
Опять же, я не хочу преобразовывать данные на стороне JNI в растровое изображение Java, чтобы иметь возможность выполнять эти операции.
Оказывается, есть некоторые библиотеки, которые предлагают много функций (например, JavaCV), но они довольно большие, и я не совсем уверен в их возможностях, и если они действительно выполняют декодирование на стороне JNI, поэтому я бы предпочел чтобы иметь возможность узнать, что возможно через встроенную функцию JNI Android вместо этого.
вопрос
Какие функции доступны для работы с изображениями на стороне JNI на Android?
например, как я могу запустить распознавание лиц на растровых изображениях, применять матрицы, растровые изображения с уменьшением выборки, растровые растровые изображения и т. д.?
для некоторых операций я уже могу придумать, как их реализовать (масштабирование изображений довольно легко, а википедия может сильно помочь), но некоторые очень сложны.
даже если я сам выполняю операции, возможно, другие сделали это гораздо эффективнее, думая о стольких оптимизациях, которые может иметь C/C++.
действительно ли я сам по себе при переходе на сторону JNI Android, где мне нужно реализовать все с нуля?
просто чтобы прояснить, что меня интересует, это:
входное растровое изображение в java -> манипулирование изображениями исключительно в JNI и C/C++ (без преобразования в объекты java) -> выходное растровое изображение в java.
2 ответа
"Встроенная функция JNI Android" - это своего рода оксюморон. Технически правильно, что многие Java-классы Android Framework используют JNI где-то в цепочке для вызова собственных библиотек.
Но есть три оговорки в отношении этого утверждения.
Это "детали реализации", и они могут быть изменены без предварительного уведомления в любом следующем выпуске Android, или любой версии (например, Kindle), или даже OEM-версии, которая не считается "вилкой" (например, созданной Samsung или для Quallcom). SOC).
Реализация собственных методов в основных классах Java отличается от "классического" JNI. Эти методы предварительно загружаются и кешируются JVM и поэтому не страдают от большинства накладных расходов, типичных для вызовов JNI.
Ваша 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) вместо преобразования его в RGB и обратно в YUV в android.media.FaceDetector.findFaces (). Если ваш буфер YUV происходит из Java, вы можете создать свой собственный класс YuvFaceDetector
которая будет копией android.media.FaceDetector с той лишь разницей, что YuvFaceDetector.findFaces()
будет принимать только значения Y (яркости) вместо растрового изображения и избегать преобразования RGB в Y.
Некоторые другие ситуации не так просты, как это. Например, видеокодеки тесно связаны с аппаратной платформой, и вы не можете просто скопировать код из libstagefright.so в ваш проект. Кодек JPEG это особый зверь. В современных системах (IIRC, начиная с 2.2) можно ожидать /system/lib/libjpeg.so
присутствовать. Но многие платформы также имеют гораздо более эффективные реализации HW кодеков Jpeg через libstagefright.so
или OpenMAX, и часто они используются в методах android.graphics.Bitmap.compress() и android.graphics.BitmapFactory.decode***().
И еще есть оптимизированный libjpeg-turbo, который имеет свои преимущества перед /system/lib/libjpeg.so
,
Похоже, что ваш вопрос больше касается библиотек обработки изображений на C/C++, чем Android. С этой целью, вот некоторые другие вопросы Stackru, которые могут иметь информацию, которую вы найдете полезной:
Быстрые кроссплатформенные библиотеки обработки изображений C/C++