Android: быстрое размытие растрового изображения?

Я искал последние три дня для встроенного ускоренного аппаратного способа размытия растрового изображения с помощью android. Я наткнулся на определенные работы, такие как сжатие растрового изображения и масштабирование его снова, но этот метод дал результаты низкого качества, которые не были подходящими для моих требований к распознаванию изображений. Я также читал, что реализация свертки с шейдерами или JNI - это хороший способ, но я не могу поверить, что в этой платформе Android нет встроенного решения для этой общей цели. В настоящее время я закончил с самонастраиваемой реализацией свертки на Java, но это неловко медленно. Мой вопрос:

  • На самом деле нет встроенного решения в платформе Android?
  • В случае отсутствия: какой самый эффективный способ ускорить свертку с еще разумной сложностью внедрения и обслуживания? Должны ли мы использовать JNI, шейдеры или что-то совершенно другое?

Ответ 1

Наконец, я нашел подходящее решение:

  • RenderScript позволяет реализовать сложные вычисления, которые прозрачно масштабируются ко всем ядрам, доступным на исполняющем устройстве. Я пришел к выводу, что в отношении разумного баланса производительности и сложности реализации это лучший подход, чем JNI или шейдеры.
  • Начиная с уровня API 17, существует класс ScriptIntrinsicBlur, доступный из API. Это именно то, что я искал, а именно высокоуровневую реализацию размытия Gaussian с ускорением аппаратного ускорения.
  • ScriptIntrinsicBlur теперь является частью библиотеки поддержки Android (v8), которая поддерживает Froyo и выше (API > 8). Сообщение блога разработчика Android в поддержка библиотеки RenderScript содержит несколько основных советов о том, как его использовать.

Однако документация в классе ScriptIntrinsicBlur очень редка, и я потратил некоторое время на выяснение правильных аргументов вызова. Для размытия обычного ARGB_8888 -типного растрового изображения с именем photo, здесь они:

final RenderScript rs = RenderScript.create( myAndroidContext );
final Allocation input = Allocation.createFromBitmap( rs, photo, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT );
final Allocation output = Allocation.createTyped( rs, input.getType() );
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create( rs, Element.U8_4( rs ) );
script.setRadius( myBlurRadius /* e.g. 3.f */ );
script.setInput( input );
script.forEach( output );
output.copyTo( photo );

Ответ 2

Наверное, самым требовательным требованием является живое размытие, означающее, что вы размываете жизнь по мере изменения вида. В этой ситуации размытие не должно занимать больше 10 или около того (чтобы играть в игровые комнаты на 16 мс /60 кадров в секунду), чтобы выглядеть гладко. Этот эффект можно добиться с помощью правильных настроек даже на не очень высоких устройствах (галактика s3 и даже медленнее).

Вот как повысить производительность в нисходящем значении:

  • Используйте уменьшенные изображения: Это уменьшает количество пикселов, чтобы размыться. Также он работает для вас, когда вы хотите получить реальное размытое изображение. Кроме того, загрузка изображения и потребление памяти резко снижаются.

  • Использование Renderscript ScriptIntrinsicBlur - вероятно, не лучшее и быстрое решение в Android с 2014 года. Одна ошибка, которую я часто вижу, заключается в том, что контекст Renderscript не используется повторно, а создается каждый раз, когда используется алгоритм размытия. Имейте в виду, что RenderScript.create(this); занимает около 20 мс на Nexus 5, поэтому вы хотите этого избежать.

  • Повторное использование растровых изображений: не создавайте ненужные экземпляры и всегда используйте один и тот же экземпляр. Когда вам нужно действительно быстрое размытие, сбор мусора играет важную роль (с хорошими 10-20 мс для сбора некоторых растровых изображений). Также обрезайте и размывайте только то, что вам нужно.

  • Для живого размытия, возможно, из-за переключения контекста, невозможно размыть другой поток (даже с помощью потоков), только основной поток был достаточно быстрым, чтобы обновлять представление своевременно, с нитями, которые я видел лагами 100-300 мс

на других советах см. мой другой пост здесь fooobar.com/info/37704/...

кстати. Я сделал простое живое размытие в этом приложении: github, Playstore