一种快速毛玻璃虚化效果实现

Ô­Îijö´¦£ºwingjayµÄ²©¿Í¡£ 

ÔÚiOSÉ豸ÉÏÎÒÃÇËæ´¦¿É¼ûë²£Á§Ð§¹û£¬¶øÇÒ×î½üÔ½À´Ô½¶àµÄ³¡ºÏÓ¦Óõ½ÁËÕâÖÖÃÀ¹ÛµÄÐ黯Ч¹û£¬°üÀ¨±¾È˵ÄÒ»¸ö¿ªÔ´ÏîÄ¿BlureImageViewÒ²ÊÇÊÜ´ËÆô·¢¡£ËùÒÔ£¬Ç¡µ½ºÃ´¦µÄÐ黯Ч¹ûÄܺܺõĸÄÉÆÓû§ÌåÑ飬¶øÇÒÒ²ÄÜÈÃÄãµÄappÏԵøü¼ÓÓÅÑÅ¡£

²»¹ý£¬ÎÒÃÇÄ¿Ç°ÔÚandroidÉϺÜÉÙ¼ûµ½Ã«²£Á§Ð§¹û£¬ÎÒÈÏΪºÜÖØÒªµÄÔ­ÒòÊÇÐÔÄÜÎÊÌ⣬Ð黯һÕÅͼƬËùÐèÒªµÄʱ¼ä»áÒòÉ豸¶øÒ죬Èç¹ûΪÁËÐ黯ʹµÃÓû§ÐèÒª¿ÌÒâµÈ´ý£¬ÄÇô¾ÍÊDZ״óÓÚÀû¡£ÁíÍ⣬Google¹Ù·½ÌṩµÄrenderScriptÒ»°ãÖ»ÊÇ×öһЩС·ù¶ÈµÄÐ黯£¬ºÜÄѴﵽë²£Á§ÕâÀàÉî¶ÈÐ黯Ч¹û¡£

ËùÒÔ±¾ÎĵĽǶÈÊÇÄܹ»ÔÚandroidÉ豸ÉÏ¿ìËÙʵÏÖë²£Á§Ð§¹û¡£

blob.png

blob.png

StackBlur

Ê×ÏÈ£¬ÎªÁËʵÏÖë²£Á§Ð§¹û£¬±¾ÎIJÉÓõÄÊÇStackBlurÄ£ºýËã·¨£¬ÕâÖÖËã·¨Ó¦Ó÷dz£¹ã·º£¬Äܵõ½·Ç³£Á¼ºÃµÄë²£Á§Ð§¹û¡£ÔÚÕâÀÎÒÃÇʹÓõÄÊÇËüµÄJavaʵÏÖ´úÂëFastBlur.java¡£

public static Bitmap doBlur(Bitmap sentBitmap, int radius, boolean canReuseInBitmap)

¿ÉÒÔ¿´³ö£¬Ê¹Ó÷½·¨·Ç³£¼òµ¥£¬´«Èë´ýÐ黯µÄbitmap¡¢Ð黯³ÌÐò(Ò»°ãΪ8)¡¢ºÍÊÇ·ñÖØÓÃflag¡£

È»ºó£¬Èç¹ûÒª¶ÔÉÏÃæÕâÕÅͼƬ½øÐÐÐ黯£¬ÎÒÃÇ¿ÉÒÔͨ¹ý°ÑËüת»¯³Ébitmap´«ÈëÐ黯£¬¿´ÆðÀ´ºÜ¼òµ¥¾Í½â¾öÁË£¬µ«ÊÂʵ²¢·ÇÈç´Ë¡£

OOM

Èç¹ûÖ±½Ó°ÑÒ»ÕÅ´óͼ´«È룬ºÜÈÝÒ׾ͻᷢÉúOOMÄÚ´æÒç³ö

03-11 21:02:02.014 16727-16742/com.wingjay.jayandroid I/art: Clamp target GC heap from 109MB to 96MB
03-11 21:02:02.026 16727-16727/com.wingjay.jayandroid I/art: Clamp target GC heap from 109MB to 96MB
03-11 21:02:02.030 16727-16727/com.wingjay.jayandroid I/art: Clamp target GC heap from 109MB to 96MB
03-11 21:02:02.031 16727-16727/com.wingjay.jayandroid I/art: Forcing collection of SoftReferences for 30MB allocation
03-11 21:02:02.035 16727-16727/com.wingjay.jayandroid I/art: Clamp target GC heap from 109MB to 96MB
03-11 21:02:02.036 16727-16727/com.wingjay.jayandroid E/art: Throwing OutOfMemoryError "Failed to allocate a 32175012 byte allocation with 2648672 free bytes and 2MB until OOM"
03-11 21:02:02.036 16727-16727/com.wingjay.jayandroid D/AndroidRuntime: Shutting down VM

ÕâÊÇÎÒÖ±½Ó¶Ôԭͼ½øÐÐÐ黯µÃµ½µÄlogÐÅÏ¢¡£¿ÉÒÔ¿´³öµ±Ð黯¿ªÊ¼Ê±£¬ÐéÄâ»ú¿ªÊ¼²»¶Ï½øÐÐÄÚ´æ»ØÊÕ£¬°üÀ¨°ÑËùÓÐÈíÒýÓõÄÄÚ´æ»ØÊÕ¡£È»¶ø£¬ÈÔÈ»µ¼ÖÂÁËÄÚ´æÒç³ö¡£

ÄǾÍÒâζ×ÅÎÒÖ»ÄÜÐ黯Сͼ£¬ÕâÑù²ÅÄÜ·ÀÖ¹ÄÚ´æÒç³ö¡£µ«ÊÇÎÒ²¢²»Ïë»»ÆäËûͼ£¬ÄÇô£¬ÎÒÃǾÍÓ¦¸Ã°ÑÕâÕÅͼËõ·Å¡£

ReScale

public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) {}

ÎÒÃÇ¿ÉÒÔÀûÓÃÕâ¸öfunctionÀ´½øÐÐbitmapµÄËõ·Å¡£ÆäÖÐÇ°Èý¸ö²ÎÊýºÜÃ÷ÏÔ£¬ÆäÖпí¸ßÎÒÃÇ¿ÉÒÔÑ¡ÔñΪԭͼ³ß´çµÄ1/10£»µÚËĸöfilterÊÇÖ¸Ëõ·ÅµÄЧ¹û£¬filterΪtrueÔò»áµÃµ½Ò»¸ö±ßԵƽ»¬µÄbitmap£¬·´Ö®£¬Ôò»áµÃµ½±ßÔµ¾â³Ý¡¢pixelrelatedµÄbitmap¡£ÕâÀïÎÒÃÇÒª¶ÔËõ·ÅµÄͼƬ½øÐÐÐ黯£¬ËùÒÔÎÞËùν±ßԵЧ¹û£¬filter=false¡£

ËùÒÔ£¬ÎÒÃÇҪʹÓÃ

int scaleRatio = 10;
int blurRadius = 8;
Bitmap scaledBitmap = Bitmap.createScaledBitmap(originBitmap,
    originBitmap.getWidth() / scaleRatio,
    originBitmap.getHeight() / scaleRatio,
    false);
Bitmap blurBitmap = FastBlur.doBlur(scaledBitmap, blurRadius, true);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setImageBitmap(blurBitmap);

¿ÉÒԵõ½ÈçÏÂЧ¹û:

blob.png

blob.png

´ÓͼÖпÉÒÔ¿´³ö£¬Ê×ÏÈ¿ÉÒÔÈ·¶¨Ë¼Â·ÊǶԵģ»È»ºó£¬¿ÉÒÔ¿´³öë²£Á§Ð§¹û»¹²»ÊÇÌرðµÄÃ÷ÏÔ¡£ÎªÁ˵õ½ÈçiOSÄÇÑùµÄÐ黯Ч¹û£¬ÎÒÃÇÓÐÁ½ÖÖ·½·¨£º

  • Ôö´óscaleRatioËõ·Å±È£¬Ê¹ÓÃÒ»Ñù¸üСµÄbitmapÈ¥Ð黯¿ÉÒԵõ½¸üºÃµÄÄ£ºýЧ¹û£¬¶øÇÒÓÐÀûÓÚÕ¼ÓÃÄÚ´æµÄ¼õС£»

  • Ôö´óblurRadius£¬¿ÉÒԵõ½¸ü¸ß³Ì¶ÈµÄÐ黯£¬²»¹ý»áµ¼ÖÂCPU¸ü¼Óintensive

ÕâÀï±¾ÈËͨ¹ýÔö´óËõ·Å±ÈÀ´ÊµÑé¡£

  • scaleRatio = 20

  • scaleRatio = 35

  • scaleRatio = 50

  • scaleRatio = 100
    scaleRatio_100

ͨ¹ýÉÏÃæ¶Ô±ÈͼÎÒÃÇ¿ÉÒÔÕÒ³ö×îÊʺÏ×Ô¼ºµÄÐ黯Ч¹û¡£

Performance analysis

ÄÇô£¬ÒªÊµÏÖÕâÑùµÄЧ¹û£¬ÊÇ·ñ¾ßÓÐËðº¦Óû§ÌåÑéµÄ·çÏÕÄØ£¿ÏÂÃ棬ÎÒÃÇ´ÓÏûºÄʱ¼äºÍÕ¼¾ÝÄÚ´æµÄ½Ç¶ÈÀ´½øÐзÖÎö¡£

Time Consuming

ΪÁË·ÖÎöÐ黯һÕÅͼƬËùÏûºÄµÄʱ¼ä£¬±¾ÎÄͨ¹ýͬʱÐ黯100À´»ñȡƽ¾ùÏûºÄʱ¼ä¡£ÒÔÆÚ¶ÔÐ黯ºÄʱºÍ²»Í¬Ëõ·Å±È¶ÔºÄʱµÄÓ°ÏìµÃµ½Ò»¶¨µÄÈÏʶ¡£

long start = System.currentTimeMillis();
Bitmap scaledBitmap, blurBitmap;
int scaleRatio = 10;
int loopCount = 100
for (int i=0; i<loopCount; i++) {
  scaledBitmap = Bitmap.createScaledBitmap(originBitmap,
      originBitmap.getWidth() / scaleRatio,
      originBitmap.getHeight() / scaleRatio,
      false);
  blurBitmap = FastBlur.doBlur(scaledBitmap, 8, true);
}
Log.i("blurtime", String.valueOf(System.currentTimeMillis() - start));
  • scaleRatio = 10: ºÄʱ887ms£¬Æ½¾ùºÄʱ8.87ms;

  • scaleRatio = 20: ºÄʱ224ms£¬Æ½¾ùºÄʱ2.24ms;

  • scaleRatio = 35: ºÄʱ99ms£¬Æ½¾ùºÄʱ0.99ms;

  • scaleRatio = 50: ºÄʱ55ms£¬Æ½¾ùºÄʱ0.55ms;

  • scaleRatio = 100: ºÄʱ29ms£¬Æ½¾ùºÄʱ0.29ms;

ΪÁË·½±ã¶ÁÕßÁ˽âЧ¹û£¬ÎÒͨ¹ý¶à×éÊý¾ÝÄâºÏÁËÏÂÃæµÄÇúÏߣº

blob.png

´Ó¸ÃÄ£Äâͼ¿ÉÒÔ¿´³öʱ¼äËæ×ÅËõ·Å±ÈµÄÔö´ó¶ø²»¶Ï¼õС£¬µ±Ëõ·Å±È´ïµ½30ÒÔÉÏʱËùÏûºÄµÄʱ¼ä²»µ½1ms£¬Òò´Ë£¬ÎÒÈÏΪӦ¸ÃÊÇÍêÈ«²»»á²úÉúʱÑÓÆÆ»µÓû§ÌåÑéµÄ¡£

Memory Consuming

¼ÈȻʱ¼äûÎÊÌ⣬ÄÇô£¬Ö÷ÒªÎÊÌ⣺ÄÚ´æÕ¼ÓþÍÀ´ÁË£¬ËùÒÔÎÒÃÇÐèÒª¿¼²ìÉú³ÉÒ»ÕÅÐ黯ͼƬËùÕ¼ÓõÄÄÚ´æ¡£

ΪÁ˲âÊÔ¶ÔÒ»ÕÅͼƬ½øÐÐÐ黯ËùÕ¼ÓÃÄÚ´æµÄ±ä»¯£¬ÎÒÃǸıäÐ黯´ÎÊý£¬¼´ÐÞ¸ÄÉÏÃæµÄloopCount²¢¹Û²ì¶ÔÄÚ´æµÄ±ä»¯¡£ÆäÖÐscaleRatio = 10£¬ÒÔ»ñµÃÏà¶Ô½Ï´óµÄÄÚ´æÏûºÄ¡£

  • loopCount = 1

  • loopCount = 10

  • loopCount = 20

  • loopCount = 50

  • loopCount = 100

  • loopCount = 300

´ÓÉÏÃæµÄÄÚ´æÏûºÄͼ£¬¿ÉÒÔ¿´³öÐ黯µÄÈ·»áÕ¼ÓÃÒ»¶¨Äڴ棬Èç¹û´óÁ¿µÄÐ黯ͬʱ·¢Éú£¬Ôò»áÓÉÓÚUIÏß³ÌͻȻ¼ÓÔغܶàbitmap¶øµ¼ÖÂÄڴ涶¶¯¡£

Conclusion

Ï£Íû´ó¼ÒÈç¹ûÓÐÆäËû²âÊÔ·½·¨»òÕßÒâ¼û¶à¶àÁôÑÔ£¬´Ó¶ø¼ÌÐø¸Ä½øÐÔÄÜ¡£

¸½Éϱ¾ÎÄËù²ÉÓõÄ

²âÊÔͼ

лл£¡

Reach me

»¶Ó­¸÷λ¹Ø×¢
ÎÒµÄGithubhttps://github.com/wingjay
ºÍ
ÎҵĸöÈ˲©¿Íhttp://wingjay.com
ºÍ
ÎҵļòÊéhttp://www.jianshu.com/users/da333fd63fe5/latest_articles
ºÍ
΢²© iam_wingjayhttp://weibo.com/u/1625892654
Èç¹ûÓÐÎÊÌ⣬¿ÉÒÔ¸øÎÒÁôÑÔ»ò·¢Óʼþ[email protected]