Atualmente em um aplicativo Android que estou desenvolvendo, estou percorrendo os pixels de uma imagem para desfocá-la. Isso leva cerca de 30 segundos em uma imagem de 640x480.
Ao navegar pelos aplicativos no Android Market, deparei-me com um que inclui um recurso de desfoque e seu desfoque é muito rápido (como 5 segundos), portanto eles devem estar usando um método diferente de desfoque.
Alguém conhece uma maneira mais rápida que não seja repetir os pixels?
Respostas:
Esta é uma foto no escuro, mas você pode tentar diminuir a imagem e ampliá-la novamente. Isso pode ser feito com
Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)
. Certifique-se e defina o parâmetro filter como true. Ele será executado no código nativo para que seja mais rápido.fonte
Para futuros Googlers, aqui está um algoritmo que eu portado do Quasimondo. É uma espécie de mistura entre um desfoque de caixa e um desfoque gaussiano, é muito bonito e muito rápido também.
Atualização para pessoas que encontram o problema ArrayIndexOutOfBoundsException: @anthonycr nos comentários fornece essas informações:
fonte
for
circuito imediatamente antes do mau dereference, quer o cálculo darbs
variável ou o cálculo dosgsum
,rsum
oubsum
variáveis não estão sendo bem feito. Eu descobri que, substituindoMath.abs
porStrictMath.abs
ou alguma outraabs
implementação, a falha não ocorre. ComoStrictMath.abs
ele próprio delegaMath.abs
, parece que deve ser uma otimização ruim.Android Blur Guide 2016
com aplicativo Showcase / Benchmark e Origem no Github . Verifique também a estrutura do Blur em que estou trabalhando atualmente: Dali .
Depois de experimentar muito, agora posso dar com segurança algumas recomendações sólidas que facilitarão sua vida no Android ao usar o Android Framework.
Carregar e usar um bitmap reduzido (para imagens muito embaçadas)
Nunca use o tamanho completo de um bitmap. Quanto maior a imagem, mais precisa ser desfocada e também maior o raio de desfoque e, geralmente, quanto maior o raio de desfoque, mais tempo o algoritmo demora.
Isso carregará o bitmap com
inSampleSize
8, portanto, apenas 1/64 da imagem original. Teste o que seinSampleSize
adequa às suas necessidades, mas mantenha 2 ^ n (2,4,8, ...) para evitar a degradação da qualidade devido ao dimensionamento. Consulte o documento do Google para obter maisOutra grande vantagem é que o carregamento de bitmap será muito rápido. Nos meus primeiros testes de desfoque, percebi que o maior tempo durante todo o processo de desfoque era o carregamento da imagem. Portanto, para carregar uma imagem de 1920x1080 do disco, meu Nexus 5 precisava de 500ms, enquanto o desfoque levava apenas mais 250 ms.
Usar Renderscript
O Renderscript fornece
ScriptIntrinsicBlur
um filtro de desfoque gaussiano. Tem boa qualidade visual e é apenas o mais rápido que você consegue realisticamente no Android. O Google afirma ser "tipicamente 2-3 vezes mais rápido que uma implementação C com vários threads e, muitas vezes, 10 vezes mais rápido que uma implementação Java" . O Renderscript é realmente sofisticado (usando o dispositivo de processamento mais rápido (GPU, ISP, etc.), etc.) e também existe a biblioteca de suporte da v8, tornando-o compatível até 2.2 . Bem, pelo menos em teoria, através dos meus próprios testes e relatórios de outros desenvolvedores, parece que não é possível usar o Renderscript às cegas, pois a fragmentação de hardware / driver parece causar problemas em alguns dispositivos, mesmo com sdk lvl mais alto (por exemplo, problemas com o 4.1 Nexus S), tenha cuidado e teste em vários dispositivos. Aqui está um exemplo simples para você começar:Ao usar o suporte da v8 com o Gradle, recomendado especificamente pelo Google "porque incluem as melhorias mais recentes" , você só precisa adicionar duas linhas ao seu script de construção e usá -las
android.support.v8.renderscript
com as ferramentas de construção atuais ( sintaxe atualizada para o plugin Gradle para Android v14 + )Referência simples em um Nexus 5 - comparando o RenderScript com outras implementações java e Renderscript:
O tempo médio de execução por desfoque em diferentes tamanhos de foto
Megapixels por segundo que podem ser desfocados
Cada valor é a média de 250 rodadas.
RS_GAUSS_FAST
éScriptIntrinsicBlur
(e quase sempre o mais rápido), outros que iniciamRS_
geralmente envolvem implementações com kernels simples. Os detalhes dos algoritmos podem ser encontrados aqui . Isso não é totalmente desfocado, pois uma boa parte é a coleta de lixo que é medida. Isso pode ser visto aqui (ScriptIntrinsicBlur
em uma imagem 100x100 com cerca de 500 rodadas)Os picos são gc.
Você pode verificar por si mesmo, o aplicativo de benchmark está na playstore: BlurBenchmark
Reutiliza o bitmap sempre que possível (se for prio: performance> memory footprint)
Se você precisar de vários borrões para um desfoque ao vivo ou semelhante e sua memória permitir, ele não carrega o bitmap de drawables várias vezes, mas o mantém "em cache" em uma variável de membro. Nesse caso, tente sempre usar as mesmas variáveis, para manter a coleta de lixo no mínimo.
Verifique também a nova
inBitmap
opção ao carregar de um arquivo ou desenho que reutilize a memória de bitmap e economize tempo de coleta de lixo.Para misturar de nítido a desfocado
O método simples e ingênuo é apenas usar 2
ImageViews
, um desfocado, e o alfa desbotá-los. Mas se você quer uma aparência mais sofisticada que desbota suavemente de nítida a desfocada, confira o post de Roman Nurik sobre como fazê-lo como em seu aplicativo Muzei .Basicamente, ele explica que pré-desfoca alguns quadros com diferentes extensões de desfoque e os usa como quadros-chave em uma animação que parece realmente suave.
fonte
renderscriptSupportModeEnabled true
ou ele não será construído! Eu procurei para sempre!EDIT (abril de 2014): esta é uma página de perguntas / respostas que ainda recebe muitos acessos ao que parece. Eu sei que estou sempre recebendo votos para este post. Mas se você estiver lendo isso, precisará entender que as respostas postadas aqui (as minhas e as aceitas) estão desatualizadas. Se você deseja implementar um desfoque eficiente hoje , use o RenderScript em vez do NDK ou Java. O RenderScript é executado no Android 2.2+ (usando a Biblioteca de suporte do Android ), portanto, não há motivo para não usá-lo.
A resposta antiga segue, mas tenha cuidado, pois está desatualizada.
Para futuros Googlers², aqui está um algoritmo que eu portado do porto de Yahel do algoritmo de Quasimondo, mas usando o NDK. É baseado na resposta de Yahel, é claro. Mas isso está executando o código C nativo, por isso é mais rápido. Muito mais rapido. Tipo, 40 vezes mais rápido.
Acho que usar o NDK é como toda manipulação de imagem deve ser feita no Android ... é um pouco chato de implementar no início (leia um ótimo tutorial sobre como usar o JNI e o NDK aqui ), mas muito melhor e quase em tempo real para um muitas coisas.
Para referência, usando a função Java de Yahel, levou 10 segundos para desfocar minha imagem de 480x532 pixels com um raio de desfoque de 10. Mas levou 250ms usando a versão C nativa. E tenho certeza de que ainda pode ser otimizado ainda mais ... Acabei de fazer uma conversão idiota do código java, provavelmente há algumas manipulações que podem ser reduzidas, que não queriam gastar muito tempo refatorando a coisa toda.
Em seguida, use-o assim (considerando uma classe chamada com.insert.your.package.ClassName e uma função nativa chamada functionToBlur, conforme o código acima afirma):
Ele espera um bitmap RGB_8888!
Para usar um bitmap RGB_565, crie uma cópia convertida antes de passar o parâmetro (eca) ou altere a função para usar um novo
rgb565
tipo em vez dergba
:O problema é que se você fizer isso você não pode ler
.red
,.green
e.blue
do pixel mais, você precisa ler o byte corretamente, duh. Quando eu precisava disso antes, fiz o seguinte:Mas provavelmente há uma maneira menos idiota de fazer isso. Receio que não sou muito de codificador C de baixo nível.
fonte
r[wh]
,g[wh]
eb[wh]
parauint8_t
.pastebin.com
Este código é um trabalho perfeito para mim
fonte
Agora você pode usar ScriptIntrinsicBlur da biblioteca Renderscript para desfocar rapidamente. Aqui está como acessar a API do RenderScript. A seguir, é uma classe que fiz para desfocar Views e Bitmaps:
fonte
Isso funcionou bem para mim: Como desfocar imagens com eficiência com o RenderScript do Android
fonte
Use o Render Script conforme mencionado aqui http://blog.neteril.org/blog/2013/08/12/blurring-images-on-android/
fonte
Isso é para todas as pessoas que precisam aumentar o raio de
ScriptIntrinsicBlur
para obter um desfoque gaussiano mais difícil.Em vez de colocar o raio acima de 25, você pode reduzir a imagem e obter o mesmo resultado. Eu escrevi uma classe chamada
GaussianBlur
. Abaixo, você pode ver como usar e toda a implementação da classe.Uso:
Classe:
fonte
Obrigado @Yahel pelo código. Postando o mesmo método com suporte a desfoque de canal alfa , demorei algum tempo para fazê-lo funcionar corretamente, para que ele economizasse o tempo de alguém:
fonte
Eu usei isso antes ..
fonte
Para futuros Googlers que escolherem a abordagem NDK - eu acho o algoritmo stackblur mencionado confiável. Encontrei a implementação C ++ que não depende do SSE aqui - http://www.antigrain.com/__code/include/agg_blur.h.html#stack_blur_rgba32, que contém algumas otimizações usando tabelas estáticas como:
Eu fiz a modificação do algoritmo stackblur para sistemas com vários núcleos - ele pode ser encontrado aqui http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/ Como cada vez mais dispositivos têm 4 núcleos, as otimizações permitem Benefício de velocidade 4x.
fonte
Nicolas POMEPUY conselho. Acho que este link será útil: Efeito de desfoque para o design do Android
Exemplo de projeto no github
fonte
Tentamos implementar o desfoque do RenderScript como mencionado acima em respostas diferentes. Estávamos limitados a usar a versão v8 do RenderScript e isso nos causou muitos problemas.
Quero compartilhar nossa versão suja apenas de Java, que é lenta e deve ser feita em um encadeamento separado e, se possível, antes do uso e, portanto, persistiu.
Esta solução está longe de ser perfeita, mas cria um efeito de desfoque razoável com base no fato de que ela desenha uma versão altamente transparente da mesma imagem em cima de uma versão "nítida" quase transparente. O alfa depende da distância da origem.
Você pode ajustar alguns "números mágicos" às suas necessidades. Eu só queria compartilhar essa "solução" para todos que têm problemas com a versão de suporte de versão v8 do RenderScript.
fonte
Para aqueles que ainda têm problemas com a biblioteca de suporte ao Renderscript em chipsets x86, consulte esta postagem pelo criador da biblioteca. Parece que a correção que ele preparou não chegou ao Build Tools v20.0.0, então ele fornece os arquivos para corrigi-lo manualmente e uma breve explicação de como fazê-lo.
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
fonte
do blog Mario Viviani, pode-se usar esta solução a partir da 17 versão Android:
https://plus.google.com/+MarioViviani/posts/fhuzYkji9zz
ou
https://gist.github.com/Mariuxtheone/903c35b4927c0df18cf8
fonte
Aqui está uma sobreposição de desfoque em tempo real usando o RenderScript, que parece ser rápido o suficiente.
https://github.com/mmin18/RealtimeBlurView
fonte
Descobri que diminuir o contraste, o brilho e a saturação torna um pouco as imagens borradas mais bonitas, então eu combinei vários métodos de estouro de pilha e criei esta Classe de desfoque que lida com imagens borradas, alteração de brilho, saturação, contraste e tamanho das imagens borradas. Também pode converter imagens de drawable em bitmap e vice-versa.
fonte
No i / o 2019, a seguinte solução foi apresentada:
fonte