Android: ¿Desenfoque de bitmap rápido?

He estado buscando en los últimos tres días una forma integrada, acelerada por hardware, de embotar un bitmap con Android. Me encontré con ciertos problemas como reducir el bitmap y escalarlo de nuevo, pero este método produjo resultados de baja calidad que no eran adecuados para mis requisitos de reconocimiento de imágenes. También leí que implementar la convolución con sombreadores o JNI es una buena forma de hacerlo, pero no puedo creer que no haya una solución incorporada en el marco de Android para este propósito muy común. Actualmente, terminé con una implementación de convolución auto escrita en Java, pero es torpemente lenta. Mi pregunta es:

  • ¿ Realmente no hay una solución incorporada en el marco de Android?
  • En caso de que no haya ninguno: ¿cuál es la forma más eficiente de acelerar la convolución con una complejidad aún razonable de implementación y mantenimiento? ¿Usaremos JNI, shaders o algo completamente diferente?

Finalmente encontré una solución adecuada:

  • RenderScript permite implementar cálculos pesados ​​que se escalan de forma transparente a todos los núcleos disponibles en el dispositivo de ejecución. Llegué a la conclusión de que, con respecto a un equilibrio razonable de rendimiento y complejidad de implementación, este es un mejor enfoque que JNI o ​​shaders.
  • Desde API Nivel 17, existe la clase ScriptIntrinsicBlur disponible desde la API. Esto es exactamente lo que he estado buscando, a saber, una implementación de desenfoque gaussiano de alto nivel acelerado por hardware.
  • ScriptIntrinsicBlur ahora es parte de la biblioteca de soporte de Android (v8) que admite Froyo y superior (API> 8). La publicación de blog de desarrollador de Android en la biblioteca de soporte de RenderScript tiene algunos consejos básicos sobre cómo usarlo.

Sin embargo, la documentación en la clase ScriptIntrinsicBlur es muy rara y he dedicado más tiempo a descifrar los argumentos de invocación correctos. Para borrar una photo nombre de bitmap ordinario ARGB_8888 , aquí están:

 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 /* eg 3.f */ ); script.setInput( input ); script.forEach( output ); output.copyTo( photo ); 

Probablemente el requisito más exigente es el desenfoque en vivo, lo que significa que se difumina en vivo a medida que cambia la vista. En esta situación, un desenfoque no debería tomar más de 10 o más ms (para tener un poco de playroom en los 16ms / 60fps) para lucir sin problemas. Es posible lograr este efecto con las configuraciones correctas, incluso en dispositivos no tan avanzados (galaxy s3 e incluso más lento).

Aquí se muestra cómo mejorar el rendimiento en importancia descendente:

  1. Utilice imágenes reducidas: esto disminuye los píxeles para desenfocarlos enormemente. También funciona para ti cuando quieres una imagen real borrosa. También la carga de la imagen y el consumo de memoria se reducen drásticamente.

  2. Use Renderscript ScriptIntrinsicBlur: probablemente no haya una solución mejor / más rápida en Android a partir de 2014. Un error que a menudo veo es que el contexto de Renderscript no se reutiliza, sino que se crea cada vez que se utiliza el algoritmo de desenfoque. Te importa que RenderScript.create(this); toma alrededor de 20 ms en un Nexus 5, por lo que desea evitar esto.

  3. Reutilizar mapas de bits: no cree instancias innecesarias y siempre use la misma instancia. Cuando necesita borrosidad realmente rápida, la recolección de basura juega un papel importante (tomando unos buenos 10-20 ms para la recolección de algunos mapas de bits). También recorte y difumine solo lo que necesita.

  4. Para un desenfoque en vivo, probablemente debido al cambio de contexto, no es posible desenfocar en otro subproceso (incluso con grupos de subprocesos), solo el subproceso principal fue lo suficientemente rápido como para mantener la vista actualizada oportunamente, con subprocesos vi desfase de 100-300 ms.

en más consejos, vea mi otra publicación aquí https://stackoverflow.com/a/23119957/774398

por cierto. Hice un desenfoque en vivo simple en esta aplicación: github , Playstore