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:
J'ai finalement trouvé une solution adaptée:
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 );
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:
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.
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.
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.
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