Android: blur Bitmap rapide?

J'ai cherché ces trois derniers jours un moyen intégré et accéléré par le matériel de flouer un bitmap avec android. Je suis tombé sur certaines solutions de contournement comme la réduction du bitmap et sa mise à l'échelle à nouveau, mais cette méthode a produit des résultats de faible qualité qui ne convenaient pas à mes exigences de reconnaissance d'image. J'ai aussi lu que l'implémentation de convolution avec des shaders ou JNI est un bon moyen d'aller, mais je ne peux pas croire qu'il n'y a pas de solution intégrée dans le framework Android pour cela but commun. Actuellement, je me suis retrouvé avec une implémentation de convolution auto-écrite en Java, mais elle est maladroitement lente. Ma question Est:

  • y at-il vraiment pas de solution intégrée dans le cadre Android?
  • au cas où il n'y en aurait pas: quel est le moyen le plus efficace d'accélérer la convolution avec une complexité d'implémentation et de maintenance encore raisonnable? Allons-nous utiliser JNI, shaders ou quelque chose de complètement différent?
32
demandé sur theV0ID 2013-02-21 00:10:04

2 réponses

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

  • RenderScript permet d'implémenter des calculs lourds qui sont mis à l'échelle de manière transparente à tous les cœurs disponibles sur le périphérique d'exécution. Je suis arrivé à la conclusion qu'en ce qui concerne un équilibre raisonnable entre la performance et la complexité de la mise en œuvre, c'est une meilleure approche que JNI ou shaders.
  • depuis le niveau 17 de L'API, la classe ScriptIntrinsicBlur est disponible à partir de L'API. C'est exactement ce que j'ai je cherchais, à savoir une implémentation de flou gaussien de haut niveau et accélérée par le matériel.
  • ScriptIntrinsicBlur fait maintenant partie de la bibliothèque de support android (v8) qui prend en charge Froyo et ci-dessus (API>8). Le blog du développeur android sur le support RenderScript bibliothèque 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 flouter un bitmap ordinaire ARGB_8888-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 );
69
répondu theV0ID 2014-08-30 17:53:31

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

Voici comment améliorer les performances en importance décroissante:

  1. Utiliser des images à échelle réduite: Cela diminue les pixels pour brouiller énormément. Aussi il travaille pour vous quand vous voulez une vraie image floue. Le chargement des images et la consommation de mémoire sont également considérablement réduits.

  2. Utilisez Renderscript ScriptIntrinsicBlur-il n'y a probablement pas une 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é. Rappelez-vous que RenderScript.create(this); prend environ 20ms sur un Nexus 5, donc vous voulez éviter ce.

  3. Réutiliser 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 collecte des ordures joue un rôle majeur (en prenant un bon 10-20 ms pour collecter des bitmaps). Aussi recadrer et flou seulement 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 threadpools), seul le thread principal était assez rapide pour garder la vue mise à jour en temps opportun, avec threads j'ai vu des décalages de 100-300ms

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

Btw. J'ai fait un simple live flou dans cette application: github, Playstore

11
répondu for3st 2017-05-23 11:53:31