Actualmente en una aplicación de Android que estoy desarrollando, estoy recorriendo los píxeles de una imagen para desenfocarla. Esto toma alrededor de 30 segundos en una imagen de 640x480.
Mientras navegaba por las aplicaciones en Android Market, me encontré con una que incluye una función de desenfoque y su desenfoque es muy rápido (como 5 segundos), por lo que deben estar usando un método diferente de desenfoque.
¿Alguien conoce una forma más rápida que no sea recorrer los píxeles?
Respuestas:
Esta es una toma en la oscuridad, pero puede intentar reducir la imagen y luego agrandarla nuevamente. Esto se puede hacer con
Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)
. Asegúrese de establecer el parámetro de filtro en verdadero. Se ejecutará en código nativo, por lo que podría ser más rápido.fuente
Para futuros Googlers, aquí hay un algoritmo que porté desde Quasimondo. Es una especie de mezcla entre un desenfoque de caja y un desenfoque gaussiano, también es muy bonito y bastante rápido.
Actualización para las personas que se encuentran con el problema ArrayIndexOutOfBoundsException : @anthonycr en los comentarios proporciona esta información:
fuente
for
bucle inmediatamente antes de la mala eliminar la referencia, ya sea el cálculo de larbs
variable o el cálculo de losgsum
,rsum
obsum
variables no se está haciendo bien. Descubrí que al reemplazarMath.abs
conStrictMath.abs
o alguna otraabs
implementación, el bloqueo no ocurre. Como enStrictMath.abs
sí mismo delegaMath.abs
, parece que debe ser una mala optimización.Android Blur Guide 2016
con Showcase / Benchmark App y Source en Github . Consulte también el marco de Blur en el que estoy trabajando actualmente: Dali .
Después de experimentar mucho, ahora puedo darte algunas recomendaciones sólidas que te harán la vida más fácil en Android cuando uses Android Framework.
Cargue y use un mapa de bits reducido (para imágenes muy borrosas)
Nunca use un tamaño completo de un mapa de bits. Cuanto más grande es la imagen, más necesita ser borrosa y también más alto debe ser el radio de desenfoque y, por lo general, cuanto mayor sea el radio de desenfoque, más tiempo tomará el algoritmo.
Esto cargará el mapa de bits con
inSampleSize
8, por lo que solo 1/64 de la imagen original. Pruebe lo que seinSampleSize
adapte a sus necesidades, pero manténgalo 2 ^ n (2,4,8, ...) para evitar degradar la calidad debido al escalado. Consulte el documento de Google para obtener más información.Otra gran ventaja es que la carga de mapas de bits será realmente rápida. En mis primeras pruebas de desenfoque, pensé que el tiempo más largo durante todo el proceso de desenfoque fue la carga de la imagen. Entonces, para cargar una imagen de 1920x1080 desde el disco, mi Nexus 5 necesitó 500 ms, mientras que el desenfoque solo tomó otros 250 ms más o menos.
Use Renderscript
Renderscript proporciona
ScriptIntrinsicBlur
cuál es un filtro de desenfoque gaussiano. Tiene buena calidad visual y es el más rápido que obtienes de forma realista en Android. Google afirma ser "típicamente 2-3 veces más rápido que una implementación C multiproceso y, a menudo, 10 veces más rápido que una implementación Java" . Renderscript es realmente sofisticado (utilizando el dispositivo de procesamiento más rápido (GPU, ISP, etc.), etc.) y también existe la biblioteca de soporte v8 para que sea compatible hasta 2.2. Bueno, al menos en teoría, a través de mis propias pruebas e informes de otros desarrolladores, parece que no es posible usar Renderscript a ciegas, ya que la fragmentación del hardware / controlador parece causar problemas con algunos dispositivos, incluso con un nivel de SDK más alto (por ejemplo, tuve problemas con el 4.1 Nexus S), así que tenga cuidado y pruebe en muchos dispositivos. Aquí hay un ejemplo simple que lo ayudará a comenzar:Cuando se utiliza el soporte v8 con Gradle, que Google recomienda específicamente "porque incluyen las últimas mejoras" , solo necesita agregar 2 líneas a su script de compilación y usarlo
android.support.v8.renderscript
con las herramientas de compilación actuales ( sintaxis actualizada para el complemento Android Gradle v14 + )Punto de referencia simple en un Nexus 5: comparación de RenderScript con otras implementaciones de Java y Renderscript diferentes:
El tiempo de ejecución promedio por desenfoque en diferentes tamaños de imagen
Megapíxeles por segundo que pueden ser borrosos
Cada valor es el promedio de 250 rondas.
RS_GAUSS_FAST
esScriptIntrinsicBlur
(y casi siempre el más rápido), otros que comienzanRS_
son en su mayoría implementaciones complicadas con núcleos simples. Los detalles de los algoritmos se pueden encontrar aquí . Esto no es puramente borroso, ya que una buena parte es la recolección de basura que se mide. Esto se puede ver aquí (ScriptIntrinsicBlur
en una imagen de 100x100 con aproximadamente 500 rondas)Los picos son gc.
Puede comprobarlo usted mismo, la aplicación de referencia está en la Play Store: BlurBenchmark
Reutiliza Bitmap siempre que sea posible (si prio: rendimiento> huella de memoria)
Si necesita múltiples desenfoques para un desenfoque en vivo o similar y su memoria lo permite, no cargue el mapa de bits de los dibujos varias veces, sino que lo mantenga "en caché" en una variable miembro. En este caso, siempre trate de usar las mismas variables, para mantener la recolección de basura al mínimo.
También revise la nueva
inBitmap
opción al cargar desde un archivo o dibujable que reutilizará la memoria de mapa de bits y ahorrará tiempo de recolección de basura.Para mezclar de nítido a borroso
El método simple e ingenuo es usar 2
ImageViews
, uno borroso y alfa desvanecerse. Pero si desea un aspecto más sofisticado que se desvanezca suavemente de nítido a borroso, consulte la publicación de Roman Nurik sobre cómo hacerlo en su aplicación Muzei .Básicamente, explica que difumina previamente algunos fotogramas con diferentes extensiones de desenfoque y los usa como fotogramas clave en una animación que se ve realmente suave.
fuente
renderscriptSupportModeEnabled true
o no se construirá! ¡Busqué por siempre!EDITAR (abril de 2014): Esta es una página de preguntas / respuestas que todavía recibe muchos éxitos, parece. Sé que siempre recibo votos positivos para esta publicación. Pero si está leyendo esto, debe darse cuenta de que las respuestas publicadas aquí (tanto la mía como la respuesta aceptada) están desactualizadas. Si desea implementar un desenfoque eficiente hoy , debe usar RenderScript en lugar de NDK o Java. RenderScript se ejecuta en Android 2.2+ (usando la Biblioteca de soporte de Android ), por lo que no hay razón para no usarlo.
La vieja respuesta sigue, pero ten cuidado ya que está desactualizada.
Para los futuros Googlers, aquí hay un algoritmo que porté desde el puerto de Yahel del algoritmo de Quasimondo, pero usando el NDK. Se basa en la respuesta de Yahel, por supuesto. Pero esto está ejecutando código C nativo, por lo que es más rápido. Mucho mas rápido. Como, 40 veces más rápido.
Me parece que usar el NDK es cómo se debe hacer toda la manipulación de imágenes en Android ... es algo molesto implementarlo al principio (lea un excelente tutorial sobre el uso de JNI y el NDK aquí ), pero mucho mejor, y casi en tiempo real para un muchas cosas.
Como referencia, utilizando la función Java de Yahel, tardé 10 segundos en desenfocar mi imagen de 480x532 píxeles con un radio de desenfoque de 10. Pero tomó 250 ms usando la versión nativa de C. Y estoy bastante seguro de que aún puede optimizarse aún más ... Acabo de hacer una conversión tonta del código de Java, probablemente hay algunas manipulaciones que pueden acortarse, no quería pasar demasiado tiempo refactorizando todo el asunto.
Luego úselo de esta manera (considerando una clase llamada com.insert.your.package.ClassName y una función nativa llamada functionToBlur, como dice el código anterior):
¡Espera un mapa de bits RGB_8888!
Para usar un mapa de bits RGB_565, cree una copia convertida antes de pasar el parámetro (yuck) o cambie la función para usar un nuevo
rgb565
tipo en lugar dergba
:El problema es que si haces eso no puedes leer
.red
,.green
y.blue
del píxel más, necesitas leer el byte correctamente, duh. Cuando lo necesitaba antes, hice esto:Pero probablemente haya una forma menos tonta de hacerlo. Me temo que no soy un codificador C de bajo nivel.
fuente
r[wh]
,g[wh]
yb[wh]
auint8_t
.pastebin.com
Este código es perfecto para mi
fuente
Ahora puede usar ScriptIntrinsicBlur de la biblioteca RenderScript para desenfocar rápidamente. Aquí se explica cómo acceder a la API de RenderScript. La siguiente es una clase que hice para difuminar vistas y mapas de bits:
fuente
Esto funcionó bien para mí: cómo desenfocar imágenes de manera eficiente con RenderScript de Android
fuente
Use Render Script como se menciona aquí http://blog.neteril.org/blog/2013/08/12/blurring-images-on-android/
fuente
Esto es para todas las personas que necesitan aumentar el radio de
ScriptIntrinsicBlur
para obtener un desenfoque gaussiano más difícil.En lugar de poner el radio más de 25, puede reducir la imagen y obtener el mismo resultado. Escribí una clase llamada
GaussianBlur
. A continuación puede ver cómo usar, y la implementación de toda la clase.Uso:
Clase:
fuente
Gracias @Yahel por el código. Publicar el mismo método con soporte de desenfoque de canal alfa ya que me tomó un tiempo hacer que funcione correctamente para que pueda ahorrarle tiempo a alguien:
fuente
Usé esto antes ...
fuente
Para los futuros Googlers que eligen el enfoque NDK, encuentro un algoritmo confiable de stackblur mencionado. Encontré la implementación de C ++ que no se basa en SSE aquí: http://www.antigrain.com/__code/include/agg_blur.h.html#stack_blur_rgba32 que contiene algunas optimizaciones utilizando tablas estáticas como:
Modifiqué el algoritmo stackblur para sistemas de múltiples núcleos. Puede encontrarlo aquí http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/ A medida que más y más dispositivos tienen 4 núcleos, las optimizaciones dan Beneficio de velocidad 4x.
fuente
Nicolas POMEPUY consejos. Creo que este enlace será útil: efecto de desenfoque para el diseño de Android
Proyecto de muestra en github
fuente
Intentamos implementar RenderScript blur como se mencionó anteriormente en diferentes respuestas. Estábamos limitados a usar la versión v8 RenderScript y eso nos causó muchos problemas.
Quiero compartir nuestra versión sucia de Java, que es lenta y debe hacerse en un hilo separado y, si es posible, antes del uso y, por lo tanto, persistió.
Esta solución está lejos de ser perfecta, pero crea un efecto de desenfoque razonable basado en el hecho de que dibuja una versión altamente transparente de la misma imagen sobre una versión "nítida" apenas transparente. El alfa depende de la distancia al origen.
Puede ajustar algunos "números mágicos" a sus necesidades. Solo quería compartir esa "solución" para todos los que tienen problemas con la versión de soporte v8 de RenderScript.
fuente
Para aquellos que todavía tienen problemas con la biblioteca de soporte de Renderscript en chipsets x86, eche un vistazo a esta publicación del creador de la biblioteca. Parece que la solución que preparó no llegó de alguna manera a Build Tools v20.0.0, por lo que proporciona los archivos para solucionarlo manualmente y una breve explicación de cómo hacerlo.
https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&groupby=&sort=&id=71347
fuente
del blog Mario Viviani se puede usar esta solución desde la versión 17 de Android:
https://plus.google.com/+MarioViviani/posts/fhuzYkji9zz
o
https://gist.github.com/Mariuxtheone/903c35b4927c0df18cf8
fuente
Aquí hay una superposición de desenfoque en tiempo real usando RenderScript, que parece ser lo suficientemente rápido.
https://github.com/mmin18/RealtimeBlurView
fuente
Descubrí que disminuir un poco el contraste, el brillo y la saturación hace que las imágenes borrosas sean más bonitas, así que combiné varios métodos de desbordamiento de pila e hice esta clase de desenfoque que se ocupa de imágenes borrosas, cambiando el brillo, la saturación, el contraste y el tamaño de las imágenes borrosas. También puede convertir imágenes de dibujables a mapas de bits y viceversa.
fuente
En el i / o 2019 se presentó la siguiente solución:
fuente