Androidダイナミックガウスぼかし効果教程


前に書く
最近ずっと完成プロジェクトの準備をしています。ぼんやりした効果を使うかもしれないと考えて、ガウスぼかし効果の実現を勉強しました。有名なのはFastBlurとそれから派生したいくつかの最適化案です。そして今日言いたいRenderScriptです。
これは今勉強しなければならないものですから、画像処理とレンダリングの問題については触れません。でも使っているうちに、同じボケ効果を実現することができますが、効率の違いは本当に大きいと実感しました。
この文章が実現したガウスぼかしは以下の文章に基づいて勉強したものです。まず紹介してください。本文の内容は内容と同じです。もう少し詳しく説明しただけで、コードの中の部分が論理と細部の処理を実現するように修正しました。しかし、主体の内容は変わらないので、どの文章を選んで勉強しても同じです。
このようなガウスぼかし効果をどうやって実現するかを見てみます。

簡単にRenderscriptを話します。
効果の実現はRenderscriptに基づいているので、まずは確認する必要があります。
その公式文書から見れば、話はとてもあやふやです。私たちは少しだけ知っていたらいいです。
RenderScript is a frame ewark for running computationlyintenssive tasms atハイテンションperformance on Android.
RenderscriptはAndroidプラットフォームで高性能計算を行うフレームです。
高性能計算である以上、RenderScriptは画像に対する処理が非常に強いので、ガウスぼかしを実現するにはまだいい選択です。
それはどう使いますか?公式文書から見れば、JavaコードにRenderscriptを使う必要があるなら、android.rendersscriptまたはandroid.support.v 8 rendersscriptのAPIに依存しなければならない。APIがある以上、やりやすいです。
以下、簡単に使用手順を説明します。これも公式文書の説明です。
  • まずContectを通じてRenderscriptを作成します。
  • 次に作成されたRenderscriptによって自分の必要なスクリプト(Script Intrinic)を作成します。例えばここでぼやける必要があります。それはScript Intrinic Blurです。
  • その後、少なくともAllocationクラスを作成し、メモリ空間を割り当てます。
  • は次に、ボケ処理などの画像を処理する。
  • 処理が完了したら、先ほどのAllocationクラスが割り当てられたメモリ空間を満たす必要があります。
  • は最後に、いくつかのリソースを選択的に回収することができる。
  • 文書の中の説明はいつも決まりがよくて、分かりにくいです。元の博主の水長天コードと合わせて、手順を見てみます。
    
    /**
     * @author Qiushui
     * @description        
     * @revision Xiarui 16.09.05
     */
    public class BlurBitmapUtil {
      //      
      private static final float BITMAP_SCALE = 0.4f;
    
      /**
       *          
       *
       * @param context      
       * @param image         
       * @return         
       */
      public static Bitmap blurBitmap(Context context, Bitmap image,float blurRadius) {
        //           
        int width = Math.round(image.getWidth() * BITMAP_SCALE);
        int height = Math.round(image.getHeight() * BITMAP_SCALE);
    
        //                
        Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
        //             
        Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
    
        //   RenderScript    
        RenderScript rs = RenderScript.create(context);
        //          RenderScript     
        ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
    
        //   RenderScript     VM     ,      Allocation           
        //   Allocation            ,    copyTo()       
        Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
        Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
    
        //          , 25f      
        blurScript.setRadius(blurRadius);
        //   blurScript       
        blurScript.setInput(tmpIn);
        //              
        blurScript.forEach(tmpOut);
    
        //       Allocation 
        tmpOut.copyTo(outputBitmap);
    
        return outputBitmap;
      }
    }
    
    
    上はガウスのはっきりしないコードを処理して、その中の注釈の書いたのは非常に詳しくて、しかもすでにピクチャーをスケーリングして処理しました。先ほどの手順に合わせて、皆さんは大体の印象があるはずです。本当にわからなくても大丈夫です。これは工具類です。直接にCopyに来てください。
    もちろん、元のブログ主はコードを車輪にパッケージしました。直接プロジェクトの中でGradeを引用してもいいですが、ソースはやはり見てみたいです。
    簡単なボケ
    はい、大体の印象がありました。ガウスぼかし効果の実現方法を見てみましょう。
    まず、プロジェクトの中で元のブックパッケージのホイールを直接引用することができます。
    comple'comp.qiushu:blurredview:0.8.1'
    引用したくないなら、現在のModuleのbuild.gradleに下記のコードを追加しなければなりません。
    
    defaultConfig {
      renderscriptTargetApi 19
      renderscriptSupportModeEnabled true
    }
    
    などを構築して使えばいいです。構築に失敗したら、ミニSdk Versionを19に設定するだけでいいです。しばらくは原因が分かりません。でも、StockOverflowからこれはBugだと分かりました。深く追究する必要はありません。
    今コードの実現を見にきて、まずファイルの中でImageViewについて、何も言いにくいことはなくて、上のぼんやりしているピクチャーのツール種類から見抜くことができて、ガウスのはっきりしない効果のピクチャーを獲得したいならば、3つのものが必要です:
    Contect:コンテキストオブジェクト
    Bitmap:ぼやけた写真が必要です。
    BlurRadius:ぼかし程度
    ここで注意が必要です。
    現在のスキームはPNG形式の画像にしか適用されません。画像のサイズは一番小さい方がいいです。コードの中で画像をスケーリングしましたが、カードトンの場合もあります。
    今は写真とぼかしさを設定すればいいです。
    
    /**
     *    View
     */
    @SuppressWarnings("deprecation")
    private void initView() {
      basicImage = (ImageView) findViewById(R.id.iv_basic_pic);
      //     
      Bitmap initBitmap = BitmapUtil.drawableToBitmap(getResources().getDrawable(R.raw.pic));
      //          
      Bitmap blurBitmap = BlurBitmapUtil.blurBitmap(this, initBitmap, 20f);
      basicImage.setImageBitmap(blurBitmap);
    }
    
    運行図を見てみます。

    写真はぼかし効果があり、しかもスピードが速いので、全体的にBlurBitmapUtil.blurBitmap()によってぼやけ効果が得られます。
    カスタムぼかしコントロール
    元のブロガーの車輪の中に私達のためにカスタマイズしたBlurredViewを封入しました。最初はカスタマイズする必要がないと思いました。その後、カスタムの原因は動的ぼかし効果を実現する必要があることがわかった。
    なぜ手作業であいまいさを設定できないですか?彼の説明は:
    上のコードを使ってリアルタイムでレンダリングすると、インターフェースの深刻なカートンが発生します。
    私も自分で試してみましたが、確かにカードがあります。彼が動的ぼかし処理を実現する案はこうである。
    「まず画像を最大程度のぼかし処理してから、原図をぼかした後の画像の上に置き、原図の透明度(Alpha値)を常に変化させて動的ぼかし効果を実現します。」
    この案は確かに効果的な動きを巧みに実現していますが、この方式を使うには二つの写真が必要です。コードに直接書くと、二つのコントロールが必要です。画像が多いと、明らかに望ましくないです。だから、車輪の中にはカスタムのBlurredViewがあります。
    でも、このBlurredViewのパッケージはあまりよくないです。一部の内容を削除しました。原因は後でまた話します。まずコアコードを見てみます。
    まず、カスタムBlurredViewはRelativeLayoutに継承されています。レイアウトファイルでは、ImageViewが2つあり、重複しています。
    
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
           android:layout_width="match_parent"
           android:layout_height="match_parent">
    
      <ImageView
        android:id="@+id/blurredview_blurred_img"
        .../>
    
      <ImageView
        android:id="@+id/blurredview_origin_img"
        .../>
    
    </FrameLayout>
    
    
    いくつかの属性も定義されています。
    
    <resources>
      <declare-styleable name="BlurredView">
        <attr name="src" format="reference"/>
        <attr name="disableBlurred" format="boolean"/>
      </declare-styleable>
    </resources>
    
    一つは設定画像で、一つは設定がぼやけないかどうかを設定します。最後にBlurredView類です。コードは以下の通りです。大量に削除されました。コアコードだけを貼り付けます。
    
    /**
     * @author Qiushui
     * @description      View 
     * @revision Xiarui 16.09.05
     */
    public class BlurredView extends RelativeLayout {
    
      /*==========      ==========*/
      private Context mContext;//     
      private static final int ALPHA_MAX_VALUE = 255;//     
      private static final float BLUR_RADIUS = 25f;//     ( 0.0 25.0  )
    
      /*==========      ==========*/
      private ImageView mOriginImg;//  ImageView
      private ImageView mBlurredImg;//    ImageView
      private Bitmap mBlurredBitmap;//    Bitmap
      private Bitmap mOriginBitmap;//  Bitmap
    
      /*==========      ==========*/
      private boolean isDisableBlurred;//        
    
      ...
    
      /**
       *               
       *
       * @param blurredBitmap       
       */
      public void setBlurredImg(Bitmap blurredBitmap) {
        if (null != blurredBitmap) {
          mOriginBitmap = blurredBitmap;
          mBlurredBitmap = BlurBitmapUtil.blurBitmap(mContext, blurredBitmap, BLUR_RADIUS);
          setImageView();
        }
      }
      ...
    
      /**
       *   ImageView
       */
      private void setImageView() {
        mBlurredImg.setImageBitmap(mBlurredBitmap);
        mOriginImg.setImageBitmap(mOriginBitmap);
      }
    
      /**
       *       
       *
       * @param level     ,     0~100   .
       */
      @SuppressWarnings("deprecation")
      public void setBlurredLevel(int level) {
        //              
        if (level < 0 || level > 100) {
          throw new IllegalStateException("No validate level, the value must be 0~100");
        }
    
        //        
        if (isDisableBlurred) {
          return;
        }
    
        //     
        mOriginImg.setAlpha((int) (ALPHA_MAX_VALUE - level * 2.55));
      }
    
      ...
    }
    
    
    コードから見られますが、一番核心となるのは次の3つの方法です。
    setBlurredImg(Bitmap bluredBitmap):写真を設定し、2つをコピーする。
    setImageView():2つのImageViewに対応する画像を設定し、内部呼び出しを行います。
    set BlurredLevel:透明度を設定する。
    構想は先に1枚のピクチャーを選定して、1枚は原図として、1枚ははっきりしない処理の過ぎた図とします。この二つの図をそれぞれカスタムBlurredViewの二つのImageViewに設定して、最後にぼやけた後のあの図の透明度を処理します。
    はい、カスタムのぼかし効果図を書きます。まずレイアウトです。簡単です。
    
     <com.blurdemo.view.BlurredView
        android:id="@+id/bv_custom_blur"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:src="@raw/pic"
        app:disableBlurred="false" />
    画像が設定されていて、オープンぼかしが設定されています。Activityでは透明度を設定すればいいです。
    
    private void initView() {
        customBView = (BlurredView) findViewById(R.id.bv_custom_blur);
        //     
        customBView.setBlurredLevel(100);
      }
    
    効果図は上の図と同じです。ここでは繰り返し貼り付けません。コードは簡単に多く見られますが、簡単なだけではカスタムViewの役割ではなく、次の動的ぼかし効果の実現に役立ちます。
    動的ぼかし
    まず、動的ぼかし効果とは何かを見てみましょう。

    画面に触れると背景のぼかしさが変わります。ぼかしさを直接設定するなら、元ブロガーが言ったように、2枚の写真で実現できます。
    大体の考えは、上の写真のぼかし処理、下の写真は処理しないで、ジェスチャーで上のぼかした写真の透明度を変えてもいいです。
    前のコードとほとんど同じです。ワンタッチイベントを書き直すだけでいいです。
    
    /**
     *    View
     */
    private void initView() {
      customBView = (BlurredView) findViewById(R.id.bv_dynamic_blur);
      //       
      initLevel = 100;
      customBView.setBlurredLevel(initLevel);
    }
    
    /**
     *     
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
      switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
          downY = ev.getY();
          break;
    
        case MotionEvent.ACTION_MOVE:
          float moveY = ev.getY();
          //      
          float offsetY = moveY - downY;
          //                
          int screenY = getWindowManager().getDefaultDisplay().getHeight() * 10;
          //             
          movePercent = offsetY / screenY;
          currentLevel = initLevel + (int) (movePercent * 100);
          if (currentLevel < 0) {
            currentLevel = 0;
          }
          if (currentLevel > 100) {
            currentLevel = 100;
          }
          //     
          customBView.setBlurredLevel(currentLevel);
          //        
          initLevel = currentLevel;
          break;
        case MotionEvent.ACTION_UP:
          break;
      }
      return super.onTouchEvent(ev);
    }
    
    
    コードから見れば、ここでは指のスライド距離がスクリーンのパーセントを占めていることで、変化後の透明度を計算します。コードは難しくないはずです。分かりやすいです。もちろん元ブロガーのブログでは、プログレスバーによって変更されてもいいです。
    RecycerViewと組み合わせる
    まず効果図を見てみます。この図も元のブロガーをまねて実現したものですが、ちょっと違っています。

    本来のカスタムBlurredViewの中には背景図の位置を変えるコードがいくつかあります。アップデートしたい時には背景図も移動できますが、体験から見ると効果はあまりよくないです。アップロードの過程で白を残す問題があります。
    元ブロガーは解決策を示しましたが、マニュアルで背景図の高さを上げました。しかし、これは一番いい解決方法ではないので、この機能を削除しました。もっといい実現方法を見つけてから補充します。
    今はどうやって実現しますか?まずレイアウトは次の階のカスタムBlurredViewで、上の一つはRecycerViewで、RecycerViewは二つのTypeがあります。一つは頭のレイアウトで、一つは下のリストです。詳しくは言いません。
    ポイントは依然として動的にあいまいな実現であり、上記の動的ぼかしの中で、OTouchEventを書き換える方法を採用しましたが、ここはちょうどRecycerViewです。私たちはそのスクロールによってモニターできます。つまり、OScrelListenerは動的に透明度を変更します。コアメソッドは以下の通りです。
    
     //RecyclerView     
      mainRView.setOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
          super.onScrollStateChanged(recyclerView, newState);
        }
    
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
          super.onScrolled(recyclerView, dx, dy);
          //    
          mScrollerY += dy;
          //                         
          if (Math.abs(mScrollerY) > 1000) {
            mAlpha = 100;
          } else {
            mAlpha = Math.abs(mScrollerY) / 10;
          }
          //       
          recyclerBView.setBlurredLevel(mAlpha);
        }
      });
    
    
    コードは簡単です。OScreld法で透明度を計算して動的に変えます。原理を把握すれば、実現しやすいです。
    締め括りをつける
    前のすべての動画から見られますが、走るのはまだ早いですが、Android Monitorから見ると、最初はぼやけていましたが、GPUは時間が長いので、性能面ではまだ不十分かもしれません。

    もちろんシミュレータと関係があるかもしれません。実機でテストするのはとても早いです。また、FastBlurよりも少し早いようですが、いくつかのガウスぼかし実現方法の性能をテストする暇があれば、比較してみます。
    ここでガウスぼかしを実現する方法は全部説明しました。元ブロガーの素晴らしい文章に感謝します。再度リンクを添付します。
    狭水長天Cは1分間で動的ぼかし効果を実現するように教えます。
    その他の参考資料
    RenderScript C Android Developers
    Android RenderScript入門(1)
    ガウスぼかし効果の実現方案と性能比較C lcyFox
    プロジェクトのソースコード
    BlurDemo C IamXiaRui C Github
    以上はAndroidの動的ガウスのはっきりしない効果の教程の例に対してで、ありがとうございます。