web-dev-qa-db-fra.com

Android: flou bitmap rapide?

J'ai recherché au cours des trois derniers jours un moyen intégré et accéléré par le matériel de créer une image bitmap avec Android. Je suis tombé sur certaines solutions de contournement telles que la réduction du bitmap et sa mise à l'échelle, mais cette méthode a produit des résultats de faible qualité qui ne convenaient pas à mes exigences de reconnaissance d'image. J'ai également lu que la mise en œuvre de la convolution avec des shaders ou JNI est une bonne façon de procéder, mais je ne peux pas croire qu'il n'y ait pas de solution intégrée dans le cadre Android Android pour cet objectif très courant. Actuellement, je 'ai fini avec une implémentation de convolution auto-écrite en Java, mais elle est maladroitement lente. Ma question est:

  • Existe-t-il vraiment pas de solution intégrée dans le Android framework?
  • Au cas où il n'y en aurait pas: quelle est la manière la plus efficace d'accélérer la convolution avec une complexité d'implémentation et de maintenance encore raisonnable? Allons-nous utiliser JNI, des shaders ou quelque chose de complètement différent?
32
theV0ID

J'ai finalement trouvé une solution adaptée:

  • RenderScript permet d'implémenter des calculs lourds qui sont mis à l'échelle de manière transparente pour tous les cœurs disponibles sur le périphérique d'exécution. J'en suis venu à la conclusion qu'en ce qui concerne un équilibre raisonnable entre les performances et la complexité de la mise en œuvre, il s'agit d'une meilleure approche que JNI ou les shaders.
  • Depuis l'API niveau 17, il existe la classe ScriptIntrinsicBlur disponible à partir de l'API. C'est exactement ce que je cherchais, à savoir une implémentation de flou gaussien accéléré par le matériel de haut niveau.
  • ScriptIntrinsicBlur fait maintenant partie de la bibliothèque de support Android (v8) qui prend en charge Froyo et au-dessus (API> 8). Le Android = article de blog développeur sur le supporte la bibliothèque RenderScript a quelques conseils de base sur la façon de l'utiliser.

Cependant, la documentation sur la classe ScriptIntrinsicBlur est très rare et j'ai passé plus de temps à trouver les arguments d'invocation corrects. Pour estomper un ordinaire ARGB_8888- bitmap typé nommé photo, les voici:

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 );
70
theV0ID

L'exigence la plus exigeante est probablement le flou en direct, ce qui signifie que vous flouez en direct lorsque la vue change. Dans cette situation, un flou ne devrait pas prendre plus de 10 ms environ (pour avoir une salle de jeu sur les 16 ms/60 ips) pour avoir un aspect lisse. Il est possible d'obtenir cet effet avec les bons réglages, même sur des appareils pas si haut de gamme (galaxy s3 et même plus lent).

Voici comment améliorer les performances en ordre décroissant:

  1. Utiliser des images à échelle réduite: cela réduit considérablement les pixels pour qu'ils soient flous. De plus, cela fonctionne pour vous lorsque vous voulez une vraie image floue. Le chargement d'images et la consommation de mémoire sont également considérablement réduits.

  2. Utilisez Renderscript ScriptIntrinsicBlur - il n'y a probablement pas de solution meilleure/plus rapide dans Android à partir de 2014. Une erreur que je vois souvent est que le contexte Renderscript n'est pas réutilisé, mais créé à chaque fois que l'algorithme de flou est utilisé Remarquez que RenderScript.create(this); prend environ 20 ms sur un Nexus 5, vous devez donc éviter cela.

  3. Réutilisez les bitmaps: ne créez pas d'instances inutiles et utilisez toujours la même instance. Lorsque vous avez besoin d'un flou très rapide, la récupération de place joue un rôle majeur (en prenant 10 à 20 ms pour la collecte de certaines images bitmap). Recadrez et floutez uniquement ce dont vous avez besoin.

  4. Pour un flou en direct, probablement à cause du changement de contexte, il n'est pas possible de flouter dans un autre thread (même avec des pools de threads), seul le thread principal était assez rapide pour maintenir la vue à jour en temps opportun, avec des threads j'ai vu des décalages de 100 à 300 ms

pour plus de conseils, voir mon autre article ici https://stackoverflow.com/a/23119957/774398

btw. J'ai fait un simple flou en direct dans cette application: github , Playstore

12
patrickf