Obecnie w opracowywanej przeze mnie aplikacji na Androida zapętlam piksele obrazu, aby go rozmyć. To zajmuje około 30 sekund na obrazie 640x480.
Przeglądając aplikacje w Android Market, natknąłem się na taką, która zawiera funkcję rozmycia, a ich rozmycie jest bardzo szybkie (około 5 sekund), więc muszą używać innej metody rozmycia.
Czy ktoś zna szybszy sposób niż zapętlanie pikseli?
Odpowiedzi:
To jest zdjęcie w ciemności, ale możesz spróbować zmniejszyć obraz, a następnie ponownie go powiększyć. Można to zrobić za pomocą
Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)
. Upewnij się i ustaw parametr filtru na true. Będzie działał w kodzie natywnym, więc może być szybszy.źródło
Dla przyszłych Googlerów, oto algorytm, który przeniosłem z Quasimondo. Jest to swego rodzaju połączenie rozmycia ramki z rozmyciem gaussowskim, jest również bardzo ładne i dość szybkie.
Aktualizacja dla osób napotykających problem ArrayIndexOutOfBoundsException: @anthonycr w komentarzach zawiera następujące informacje:
źródło
for
pętli bezpośrednio przed złym dereference, albo obliczanierbs
zmiennej lub obliczeniegsum
,rsum
czybsum
zmienne nie są robione w prawo. Okazało się, że przy wymianieMath.abs
zStrictMath.abs
lub innejabs
realizacji, awaria nie występuje. PonieważStrictMath.abs
sama się delegujeMath.abs
, wydaje się, że musi to być zła optymalizacja.Android Blur Guide 2016
z aplikacją Showcase / Benchmark i źródłem na Github . Sprawdź także środowisko Blur, nad którym obecnie pracuję: Dali .
Po wielu eksperymentach mogę teraz bezpiecznie dać ci solidne rekomendacje, które ułatwią Ci życie na Androidzie podczas korzystania z Android Framework.
Załaduj i użyj zmniejszonej mapy bitowej (dla bardzo rozmytych obrazów)
Nigdy nie używaj pełnego rozmiaru mapy bitowej. Im większy obraz, tym więcej musi być zamazanych, a także im większy musi być promień rozmycia, i zwykle im większy promień rozmycia, tym dłużej zajmuje algorytm.
Spowoduje to załadowanie bitmapy z
inSampleSize
8, więc tylko 1/64 oryginalnego obrazu. Sprawdź, coinSampleSize
odpowiada Twoim potrzebom, ale zachowaj 2 ^ n (2,4,8, ...), aby uniknąć pogorszenia jakości z powodu skalowania. Zobacz dokument Google, aby uzyskać więcejKolejną naprawdę dużą zaletą jest to, że ładowanie bitmap będzie bardzo szybkie. Podczas moich wczesnych testów rozmycia doszedłem do wniosku, że najdłużej podczas całego procesu rozmycia było ładowanie obrazu. Tak więc, aby załadować obraz 1920x1080 z dysku, mój Nexus 5 potrzebował 500 ms, a rozmycie trwało tylko kolejne 250 ms.
Użyj Renderscript
Renderscript zapewnia
ScriptIntrinsicBlur
filtr rozmycia Gaussa. Ma dobrą jakość wizualną i jest po prostu najszybszy, jaki masz realistycznie na Androida. Google twierdzi, że jest „zwykle 2-3 razy szybszy niż wielowątkowa implementacja C i często 10 razy szybszy niż implementacja Java” . Renderscript jest naprawdę wyrafinowany (przy użyciu najszybszego urządzenia przetwarzającego (GPU, ISP itp.) Itp.)). Dostępna jest również biblioteka obsługi v8, dzięki czemu jest kompatybilny z wersją 2.2. Cóż, przynajmniej teoretycznie, dzięki własnym testom i raportom innych deweloperów wydaje się, że nie można używać Renderscript na ślepo, ponieważ fragmentacja sprzętu / sterownika wydaje się powodować problemy z niektórymi urządzeniami, nawet z wyższym poziomem sdk lvl (np. Miałem problemy z 4.1 Nexusem S), więc bądź ostrożny i testuj na wielu urządzeniach. Oto prosty przykład, który pomoże Ci zacząć:Korzystając z obsługi wersji 8 z Gradle, która jest szczególnie zalecana przez Google „, ponieważ zawierają najnowsze ulepszenia” , wystarczy dodać tylko 2 wiersze do skryptu kompilacji i używać
android.support.v8.renderscript
z bieżącymi narzędziami kompilacji ( zaktualizowana składnia wtyczki Gradle dla Androida w wersji 14 + )Prosty test porównawczy na Nexusie 5 - porównanie RenderScript z różnymi innymi implementacjami Java i Renderscript:
Średni czas działania na rozmycie dla różnych rozmiarów zdjęć
Megapiksele na sekundę, które można zamazać
Każda wartość to średnia z 250 rund.
RS_GAUSS_FAST
jestScriptIntrinsicBlur
(i prawie zawsze najszybszy), inne, które zaczynają się od tego,RS_
są w większości implementacjami złożonymi z prostymi jądrami. Szczegóły algorytmów można znaleźć tutaj . Nie jest to czysto rozmycie, ponieważ dobrą porcją jest mierzone zbieranie śmieci. Można to zobaczyć tutaj (ScriptIntrinsicBlur
na obrazie 100 x 100 z około 500 rundami)Kolce są gc.
Możesz sam sprawdzić, czy aplikacja testowa znajduje się w sklepie internetowym: BlurBenchmark
Wykorzystuje bitmapę wszędzie tam, gdzie to możliwe (jeśli prio: wydajność> ślad pamięci)
Jeśli potrzebujesz wielu rozmycia dla rozmycia na żywo lub podobnego, a twoja pamięć pozwala, nie ładuj bitmapy z drawable wiele razy, ale przechowuj ją w pamięci podręcznej w zmiennej członka. W takim przypadku zawsze staraj się używać tych samych zmiennych, aby ograniczyć odśmiecanie do minimum.
Sprawdź także nową
inBitmap
opcję podczas ładowania z pliku lub pliku do rysowania, który ponownie wykorzysta pamięć bitmapy i zaoszczędzi czas na wyrzucanie elementów bezużytecznych.Do mieszania od ostrego do rozmytego
Prostą i naiwną metodą jest użycie 2
ImageViews
, jeden zamazany, a alfa znikną. Ale jeśli chcesz uzyskać bardziej wyrafinowany wygląd, który płynnie przechodzi od ostrego do rozmytego, zapoznaj się z postem Romana Nurika o tym, jak to zrobić w jego aplikacji Muzei .Zasadniczo wyjaśnia, że wstępnie rozmywa niektóre klatki z różnymi zakresami rozmycia i używa ich jako klatek kluczowych w animacji, która wygląda naprawdę gładko.
źródło
renderscriptSupportModeEnabled true
lub nie zbuduje się! Szukałem na zawsze!EDYCJA (kwiecień 2014): To jest strona pytań / odpowiedzi, która wciąż wydaje się bardzo trafiona. Wiem, że zawsze otrzymuję pozytywne opinie na temat tego postu. Ale jeśli to czytasz, musisz zdać sobie sprawę, że odpowiedzi zamieszczone tutaj (zarówno moja, jak i zaakceptowana odpowiedź) są nieaktualne. Jeśli chcesz dziś wdrożyć wydajne rozmycie , powinieneś użyć RenderScript zamiast NDK lub Java. RenderScript działa na Androidzie 2.2+ (przy użyciu Biblioteki pomocy Android ), więc nie ma powodu, aby go nie używać.
Następuje stara odpowiedź, ale uważaj, ponieważ jest nieaktualna.
Dla przyszłych² Googlerów, oto algorytm, który przeniosłem z portu Yahela algorytmu Quasimondo, ale używając NDK. Oczywiście opiera się na odpowiedzi Yahel. Ale działa natywny kod C, więc jest szybszy. O wiele szybciej. Na przykład 40 razy szybciej.
Uważam, że za pomocą NDK jest jak wszystko manipulacja obrazu powinno być wykonane na Androida ... to nieco irytujące do realizacji w pierwszym (czytaj świetny tutorial na użyciu JNI i NDK tutaj ), ale o wiele lepiej, a przy czasie rzeczywistym Przez dużo rzeczy.
Dla porównania, używając funkcji Java Yahel, rozmycie mojego obrazu 480 x 532 pikseli zajęło 10 sekund z promieniem rozmycia wynoszącym 10. Ale natywna wersja C. zajęła 250 ms. I jestem prawie pewien, że można go dalej optymalizować ... Właśnie zrobiłem głupią konwersję kodu Java, prawdopodobnie są pewne manipulacje, które można skrócić, nie chciałem spędzać zbyt dużo czasu na refaktoryzacji całości.
Następnie użyj go w ten sposób (biorąc pod uwagę klasę o nazwie com.insert.your.package.ClassName i natywną funkcję o nazwie functionToBlur, jak podano powyżej):
Oczekuje bitmapy RGB_8888!
Aby użyć mapy bitowej RGB_565, utwórz przekonwertowaną kopię przed przekazaniem parametru (fuj) lub zmień funkcję, aby użyć nowego
rgb565
typu zamiastrgba
:Problem polega na tym, że jeśli zrobisz to, czego nie możesz odczytać
.red
,.green
i.blue
piksela, musisz poprawnie odczytać bajt, duh. Kiedy potrzebowałem tego wcześniej, zrobiłem to:Ale prawdopodobnie jest to mniej głupi sposób. Obawiam się, że nie jestem programistą C na niskim poziomie.
źródło
r[wh]
,g[wh]
ib[wh]
douint8_t
.pastebin.com
Ten kod jest dla mnie idealny
źródło
Możesz teraz używać ScriptIntrinsicBlur z biblioteki RenderScript, aby szybko rozmazać. Oto jak uzyskać dostęp do interfejsu API RenderScript. Oto klasa, którą stworzyłem, aby rozmazać widoki i mapy bitowe:
źródło
Działa to dla mnie dobrze: Jak skutecznie zamazywać obrazy za pomocą RenderScript na Androidzie
źródło
Użyj skryptu renderowania, jak wspomniano tutaj http://blog.neteril.org/blog/2013/08/12/blurring-images-on-android/
źródło
Dotyczy to wszystkich osób, które muszą zwiększyć promień,
ScriptIntrinsicBlur
aby uzyskać mocniejsze rozmycie gaussowskie.Zamiast ustawić promień większy niż 25, możesz przeskalować obraz i uzyskać ten sam wynik. Napisałem klasę o nazwie
GaussianBlur
. Poniżej możesz zobaczyć, jak używać i implementację całej klasy.Stosowanie:
Klasa:
źródło
Dzięki @Yahel za kod. Opublikowanie tej samej metody z obsługą zamazywania kanału alfa, ponieważ zajęło mi trochę czasu, aby działała poprawnie, dzięki czemu może zaoszczędzić czyjś czas:
źródło
Użyłem tego wcześniej ...
źródło
Dla przyszłych Googlersów, którzy wybiorą podejście NDK - znajduję wiarygodny wspomniany algorytm stackblur. Znalazłem tutaj implementację C ++, która nie polega na SSE - http://www.antigrain.com/__code/include/agg_blur.h.html#stack_blur_rgba32, która zawiera pewne optymalizacje przy użyciu statycznych tabel, takich jak:
Dokonałem modyfikacji algorytmu stackblur dla systemów wielordzeniowych - można go znaleźć tutaj http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/ Ponieważ coraz więcej urządzeń ma 4 rdzenie - optymalizacje dają 4x szybsza korzyść.
źródło
Porada Nicolas POMEPUY. Myślę, że ten link będzie pomocny: Efekt rozmycia w projektowaniu Androida
Przykładowy projekt na github
źródło
Próbowaliśmy zaimplementować rozmycie RenderScript jak wspomniano powyżej w różnych odpowiedziach. Ograniczono nas do używania wersji RenderScript v8, co spowodowało wiele problemów.
Chcę udostępnić naszą brudną wersję przeznaczoną tylko dla języka Java, która jest powolna i powinna być wykonywana w osobnym wątku oraz, jeśli to możliwe, przed użyciem, a zatem trwała.
To rozwiązanie jest dalekie od ideału, ale daje rozsądny efekt rozmycia, ponieważ rysuje bardzo przezroczystą wersję tego samego obrazu na ledwo przezroczystej „ostrej” wersji. Alfa zależy od odległości do początku.
Możesz dostosować niektóre „magiczne liczby” do swoich potrzeb. Chciałem tylko udostępnić to „rozwiązanie” wszystkim, którzy mają problemy z wersją RenderScript obsługującą wersję 8.
źródło
Jeśli nadal masz problemy z biblioteką obsługi Renderscript na mikroukładach x86, zapoznaj się z tym postem twórcy biblioteki. Wygląda na to, że poprawka, którą przygotował, nie dotarła w jakiś sposób do Build Tools v20.0.0, więc udostępnia pliki do ręcznej naprawy i krótkie wyjaśnienie, jak to zrobić.
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
źródło
z bloga Mario Viviani można skorzystać z tego rozwiązania z 17 wersji Androida:
https://plus.google.com/+MarioViviani/posts/fhuzYkji9zz
lub
https://gist.github.com/Mariuxtheone/903c35b4927c0df18cf8
źródło
Oto nakładka rozmycia w czasie rzeczywistym za pomocą RenderScript, która wydaje się być wystarczająco szybka.
https://github.com/mmin18/RealtimeBlurView
źródło
Przekonałem się, że zmniejszenie kontrastu, jasności i nasycenia trochę upiększa rozmazane obrazy, dlatego połączyłem różne metody od przepełnienia stosu i stworzyłem tę klasę rozmycia, która zajmuje się rozmyciem zdjęć, zmianą jasności, nasycenia, kontrastu i rozmiaru rozmytych obrazów. Może także konwertować obrazy z rysowalnej na bitmapę i odwrotnie.
źródło
Na I / O 2019 zaprezentowano następujące rozwiązanie:
źródło