読者です 読者をやめる 読者になる 読者になる

ます’s Blog - どうでもいい記事100選

どうでもいい記事100選

iPod touch 欲しい! id:hatenablog

あたるといいな。

今年の抱負

あけましておめでとうございます。今年もよろしくお願いします。<(_ _)>
今年の干支は「龍」。龍が如く大空を駆け巡るような1年にしたい。そして満足できる1年にしたい。ただ、それだけです。
去年は本当にガッカリな1年だったので、やり場の無い怒りと共にメラメラと気持ちが燃えています。
攻めて攻めて攻めまくりたい。ガッカリする気持ちを再び味わうのはコリゴリです。
他人に迷惑がかかろうが知ったこっちゃない。。。そんな気持ちで後先を考えずに捨て身の覚悟で攻めていきたいと思います。泥水をすすろうが何しようが最終的には立った者勝ち。後は野となれ山となれ!
おみくじも大吉と幸先が良い。第二十四番という番号で不思議とピンときたんだよね。今年1年を暗示してくれてるといいなぁ。思うがままに活動していきたい。結果は後からついてくることと信じて。
f:id:masugata:20120101003622:image:medium

大晦日

久々の更新で恐縮ですが、今日は大晦日なので2011年を振り返ってみます
昨年は非常に調子が良かったので今年も継続して。。。と思っていたのですが、色んな不幸が寄ってきているような(自分から不幸に寄っていっている?)感じで、自分の年齢通りの散々(33)な1年でした。仕事納めもトラブル続き。。。_| ̄|○
干支にちなんで「飛び跳ねて」いきたかったのですが。。。気持ちだけで終わったようです。逆に兎の臆病さが全面に出て逃げ回っていたような気もします。


今年は何をやるにしても課題に突き当たって自分の思い描いていたとおりに上手くいかなかったことが多かったです。
そういったことが多くて自分の中でのやる気も徐々に萎えていき、中途半端な状態が多かったように思えます。自分自身にガッカリです。
改めて考えてみると、色んな人の思惑(邪念)に振り回されて不毛な消耗をしてしまったかな。。。と思います。ちょっと懲りているので距離を置きたい。


ようやく住宅ローンが完済できたのに次の住宅ローン(35年コース)も始まってしまうし、自分の状況も外堀から埋められているような状況で、いよいよ追い詰められている状況です。危機的状況です。もう先は長くないのかもしれない。
そんな状況ですが、炎上プロジェクトへ人身御供的に投入され某ビルに拉致られているような状態。状況を改善しようにも動くことができない。。。といった、もどかしい状況です。
今が大事な時期なのに。。。これは天命だと思ったほうがいいのかなぁ。嵐が過ぎるのを大人しく待つべきか。
気持ちも内へ内へと向かっていくことが多く、思うように活動することができませんでした。よく分らないけど、そういう時期なのかもしれない。
他にも今年は3・11の東日本大震災があったり、スティーブ・ジョブズやデニス・リッチーが死去したりと衝撃的な1年であったように思えます。


とは言っても良いこともありました。昨年に引き続きアメリカ(サンフランシスコ)に行くことができました。
一昨年は数人で行っているので守られている感が非常にありましたが、今年は一人で挑戦。何とか無事に戻ってこれることができました。
英語は全く喋れませんでしたが、ピンチの状況になると「何とかしよう!」という気持ち(生存本能?)が働いて、分からないなりに周りの空気を読みまくって何とかすることができました。行けば何とかするもんなんですね。大きな自信に繋がりました。案ずるより産むが易し。


Goolge I/Oチケット争奪戦が瞬殺だったこともあって半分くらい投げやりな感じでMicrosoftのBUILD Conferenceに申し込んだのですが、結果的には行くことができて非常に良かったです。Windows8の評価用タブレットも入手できたし、ついでにアメリカのディズニーランドに行くこともできて非常に満足です。来年も懲りずに行きたいですね。次は南半球とか欧州とか、そっち方面を狙っていきたい。


詳しくは言えないけど、なかなか面白い出会いもありました。優れている人は気持ちが前向きだし一緒に活動していて楽しいね。良い刺激を貰っています。いつまで関係が続くか分からないけど、今後も一緒に活動できれば嬉しいなぁ。
端末でいうとWindows Phoneも入手しているし、iPhone4Sも入手しているし、Galaxy Nexusも入手しているし、悪い事ばかりではなかったように思えますが。。。でも。でも。でも。やっぱりガッカリな1年でした。端末も満足に使いこなせてないし。。。来年は気合を入れて頑張ろう。_| ̄|○


今年は本当に散々な一年でしたが、段々と嘆きのフェーズから怒りのフェーズに気持ちが移りつつあるので、やり場の無い怒りをエネルギーに変えて来年は気合を入れて活動していこうと思います。来年はやるぞー!

お母さん

今日、JR山手線の恵比寿駅で非常警報が鳴り止まなずに電車がしばらく止まっていた。
非常警報を聞いていたら幼少(5歳くらい)の頃の記憶を思い出したので忘れずに書いておこう。
ここ5年くらいは物忘れが激しいのと記憶力が非常に危ういので書いて残しておかないと何をやっていたのか思い出せない時がある。
歳なのかな。。。これでも記憶力は自信があるほうだったのに。_| ̄|○


5人兄(姉)弟の3番目だった事もあってか、とにかく負けず嫌いでやんちゃで好奇心が旺盛でしたが、好奇心が災いしてちょっとした出来事がありました。
ビルやマンションには非常警報ボタンがついていると思いますが、子供の頃はボタンを押すと何が起こるか理解できておらず、軽い気持ちで押してしまったら「リーン!」と凄い音量で鳴り出しました。


どうすれば良いか全然分からず非常にうろたえていたのを覚えています。どうする事もできなかったので、何を思ったのか倉庫の脇みたいなところに一人で隠れました。


しゃがんでビクビクしていたら、背中をポンポンと叩かれて「もう駄目だ!」と思っていたところ。。。背中を叩いたのはお母さんでした。その時のお母さんがにっこり笑っていたのが印象深いです。
お母さんは何も言わずに自分に手を差し伸べてくれて(手を繋いで)そのまま一緒に家に帰ってくれました。
その時、包まれているような感じの非常に暖かい印象があったように思えます。やっぱり子供にとって、お母さんは特別な存在なんだなぁ。。。と今更ながら実感しています。


改めて振り返ってみると、自分の子供がやんちゃして大変な状況になっているのに、その状況をスルーして家に帰るっていうのも親としてどうなんだ?とは思いますが。。。不思議と家に帰ったら鳴り止んだので良しとしよう。(w




後、これに近い思い出としてはバス事件かな。
「次とまります」ボタンがあるかと思いますが、子供の頃はボタンを押すと何が起こるか理解できておらず、ボタンのランプが消えたら速攻でボタンを押してを繰り返して。。。今考えるとスゲー迷惑だな。_| ̄|○


そういえばバスの運転手さんも「降りる方いませんかー?」って散々言ってた気がするなぁ。バスの中には自分達しかいなかったで、誰がやったか運転手さんも分かっていたハズ。本当に申し訳ない。。。ただ、お母さんはその状況を華麗にスルーしてたので、あまり気にしない性格だったのかなぁ。
バスを降りて魚町銀天街にいったのですが、魚屋に置かれていたハマグリに指を挟まれて死ぬかと思いました。指が切れるかと思った。。。今思うと天罰だったね。




そこから程なくして父と母は別居をする選択をした(母は大阪の実家に戻っていった)ので、正直、お母さんとの思い出はそんなに覚えていないんだよね。
一番下の子は当時1歳未満だったこともあって母と一緒に母の実家に戻っていったけど、今更どういう顔して会えばいいか分からないな。。。自分も「実の弟です」とか言われても急に登場されても困る。(w

ミニチュア模型風(続き)

先日のですが。
ある方からミニチュア模型風は彩度と明度を少し上げれば良いとアドバイスを貰ったので確認してみました。
前回は彩度は上げていたけど明度は下げていたので全体的に暗かったのですが、今回は彩度と明度を上げているので全体的に明るいですね。状況に応じて使い分けたい。

  // ミニチュア模型風(続き)
  private Bitmap effectScaleModel( Bitmap bitmap, int range, int lineFlg, Boolean flg, Boolean SV_flg ){

    if( bitmap == null ){
      bitmap = BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true );
    }

    if( bitmap == null ){
      return bitmap;
    }

    if( bitmap.isMutable( ) != true ){
      bitmap = bitmap.copy( Bitmap.Config.ARGB_8888, true );
    }

    bitmap = effectShadeingLine( bitmap, range, lineFlg );

    if( flg != true ){
      return bitmap; 
    }

    int height   = bitmap.getHeight( );
    int width    = bitmap.getWidth( );
    int[] pixels = new int[( width * height )];
    bitmap.getPixels( pixels, 0, width, 0, 0, width, height );

    for( int YY = 0; YY < width; ++YY ){
      for( int XX = 0; XX < height; ++XX ){

        int bitmapColor = pixels[( YY + XX * width )];

        int rr = Color.red( bitmapColor );
        int gg = Color.green( bitmapColor );
        int bb = Color.blue( bitmapColor );

        // hsv[0] is Hue [0.0f .. 360.0f]
        // hsv[1] is Saturation [0.0f...1.0f]
        // hsv[2] is Value [0.0f...1.0.0f]
        float[] hsv = new float[3];
        Color.RGBToHSV( rr, gg, bb, hsv );

        if( SV_flg == true ){
          hsv[1] *= 1.2f;
          hsv[2] *= 1.2f;
        } else {
          hsv[1] *= 1.5f;
          hsv[2] -= 0.1f;
        }

        if( 1 < hsv[1] ){
          hsv[1] = 1.0f;
        } else if( hsv[1] < 0 ){
          hsv[1] = 0.0f;
        }

        if( 1 < hsv[2] ){
          hsv[2] = 1.0f;
        } else if ( hsv[2] < 0 ){
          hsv[2] = 0.0f;
        }

        pixels[( YY + XX * width )] = Color.HSVToColor( hsv );
      }
    }

    bitmap.setPixels( pixels, 0, width, 0, 0, width, height );
    
    return bitmap;
  }
  
  // ぼかし(ライン)
  private Bitmap effectShadeingLine( Bitmap bitmap, int range, int lineFlg ){

    if( bitmap == null ){
      bitmap = BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true );
    }

    if( bitmap == null ){
      return bitmap;
    }

    if( bitmap.isMutable( ) != true ){
      bitmap = bitmap.copy( Bitmap.Config.ARGB_8888, true );
    }

    int height   = bitmap.getHeight( );
    int width    = bitmap.getWidth( );
    int[] pixels = new int[( width * height )];
    bitmap.getPixels( pixels, 0, width, 0, 0, width, height );

    int i, j, ii, jj;
    int pixel = 3;

    for( i = 0; i < width; ++i ){
      for( j = 0; j < height; ++j ){

        int r, g, b;
        float sumR, sumG, sumB;
        sumR = 0.0f;
        sumG = 0.0f;
        sumB = 0.0f;

        for( ii = -pixel; ii <= pixel; ii++ ){
          for( jj = -pixel; jj <= pixel; jj++ ){

            if( ( i + ii ) < 0 || width  <= ( i + ii ) ||
                ( j + jj ) < 0 || height <= ( j + jj ) ){
              continue;
            }

            int bitmapColor = pixels[( ( i + ii ) + ( j + jj ) * width )];

            r = Color.red( bitmapColor );
            g = Color.green( bitmapColor );
            b = Color.blue( bitmapColor );

            sumR += (float)r;
            sumG += (float)g;
            sumB += (float)b;
          }
        }

        int rr, gg, bb;
        rr = (int)( sumR / Math.pow( ( 1 + ( 2 * pixel ) ), 2 ) );
        gg = (int)( sumG / Math.pow( ( 1 + ( 2 * pixel ) ), 2 ) );
        bb = (int)( sumB / Math.pow( ( 1 + ( 2 * pixel ) ), 2 ) );

        Boolean flg = false;

        if( range > 0 ){
          if( lineFlg == 1 ){
            if( !( i < ( ( width / 2 ) + range ) && ( ( width / 2 ) - range ) < i ) ){
               flg = true;
            }
            
            if( ( ( width / 2 ) - ( range * 2 ) )         <= i && i < ( ( width / 2 ) - range - ( range / 2 ) ) ||
                ( ( width / 2 ) + range + ( range / 2 ) ) <= i && i < ( ( width / 2 ) + ( range * 2 ) ) ){
              pixel = 2;
            } else if( ( ( width / 2 ) - range - ( range / 2 ) ) <= i && i < ( ( width / 2 ) - range ) ||
                       ( ( width / 2 ) + range )                 <= i && i < ( ( width / 2 ) + range + ( range / 2 ) ) ){
              pixel = 1;
            } else {
              pixel = 3;
            }
          } else {
            if( !( j < ( ( height / 2 ) + range ) && ( ( height / 2 ) - range ) < j ) ){
               flg = true;
            }
            
            if( ( ( height / 2 ) - ( range * 2 ) )         <= j && j < ( ( height / 2 ) - range - ( range / 2 ) ) ||
                ( ( height / 2 ) + range + ( range / 2 ) ) <= j && j < ( ( height / 2 ) + ( range * 2 ) ) ){
              pixel = 2;
            } else if( ( ( height / 2 ) - range - ( range / 2 ) ) <= j && j < ( ( height / 2 ) - range ) ||
                       ( ( height / 2 ) + range )                 <= j && j < ( ( height / 2 ) + range + ( range / 2 ) ) ){
              pixel = 1;
            } else {
              pixel = 3;
            }
          }
        } else {
          flg = true;
        }

        if( flg == true ){
          pixels[( i + j * width )] = Color.rgb( rr, gg, bb );
        }
      }
    }

    bitmap.setPixels( pixels, 0, width, 0, 0, width, height );

    return bitmap;
  }

ミニチュア風 オリジナル:
f:id:masugata:20110519154521:image:medium
ミニチュア風 縦(違いは詳細で見てください):
f:id:masugata:20110519154530:image:medium
ミニチュア風 横(違いは詳細で見てください):
f:id:masugata:20110519154508:image:medium
ミニチュア風 縦 彩度・明度ちょい上げ(違いは詳細で見てください):
f:id:masugata:20110525142333:image:medium
ミニチュア風 横彩度・明度ちょい上げ(違いは詳細で見てください):
f:id:masugata:20110525142346:image:medium
ミニチュア風 縦 ぼかしのみ(違いは詳細で見てください):
f:id:masugata:20110519154502:image:medium
ミニチュア風 横 ぼかしのみ(違いは詳細で見てください):
f:id:masugata:20110519154457:image:medium

ミニチュア模型風

あくまでも「風」ですが。_| ̄|○
画像の雰囲気に依存する部分もありますが、ぼかしを入れてコントラストを強めに調整する事でミニチュア模型風になるようです。もうちょっとコントラストを調整してもよい気もするけど。。。
斜め上からっていうよりかは遠目から被写体を撮ると上手くいきやすい。被写界深度がポイントのようです。

基本的にはトイカメラ風の画像を加工する処理と変わっていませんが、ぼかしを入れる部分が中心から四角を残すのではなくて縦か横のラインにしてみました。
ぼかし部分と素の部分の境界線が気になっていたので、ピクセル数を徐々に変化させています。。。多少は良くなったけど、まだまだ気になる。_| ̄|○

  // ミニチュア模型風
  private Bitmap effectScaleModel( Bitmap bitmap, int range, int lineFlg, Boolean flg ){

    if( bitmap == null ){
      bitmap = BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true );
    }

    if( bitmap == null ){
      return bitmap;
    }

    if( bitmap.isMutable( ) != true ){
      bitmap = bitmap.copy( Bitmap.Config.ARGB_8888, true );
    }

    bitmap = effectShadeingLine( bitmap, range, lineFlg );

    if( flg != true ){
      return bitmap; 
    }

    int height   = bitmap.getHeight( );
    int width    = bitmap.getWidth( );
    int[] pixels = new int[( width * height )];
    bitmap.getPixels( pixels, 0, width, 0, 0, width, height );

    for( int YY = 0; YY < width; ++YY ){
      for( int XX = 0; XX < height; ++XX ){

        int bitmapColor = pixels[( YY + XX * width )];

        int rr = Color.red( bitmapColor );
        int gg = Color.green( bitmapColor );
        int bb = Color.blue( bitmapColor );

        // hsv[0] is Hue [0.0f .. 360.0f]
        // hsv[1] is Saturation [0.0f...1.0f]
        // hsv[2] is Value [0.0f...1.0.0f]
        float[] hsv = new float[3];
        Color.RGBToHSV( rr, gg, bb, hsv );

        hsv[1] *= 1.5f;
        hsv[2] -= 0.1f;

        if( 1 < hsv[1] ){
          hsv[1] = 1.0f;
        } else if( hsv[1] < 0 ){
          hsv[1] = 0.0f;
        }

        if( 1 < hsv[2] ){
          hsv[2] = 1.0f;
        } else if ( hsv[2] < 0 ){
          hsv[2] = 0.0f;
        }

        pixels[( YY + XX * width )] = Color.HSVToColor( hsv );
      }
    }

    bitmap.setPixels( pixels, 0, width, 0, 0, width, height );
    
    return bitmap;
  }
  
  // ぼかし(ライン)
  private Bitmap effectShadeingLine( Bitmap bitmap, int range, int lineFlg ){

    if( bitmap == null ){
      bitmap = BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true );
    }

    if( bitmap == null ){
      return bitmap;
    }

    if( bitmap.isMutable( ) != true ){
      bitmap = bitmap.copy( Bitmap.Config.ARGB_8888, true );
    }

    int height   = bitmap.getHeight( );
    int width    = bitmap.getWidth( );
    int[] pixels = new int[( width * height )];
    bitmap.getPixels( pixels, 0, width, 0, 0, width, height );

    int i, j, ii, jj;
    int pixel = 3;

    for( i = 0; i < width; ++i ){
      for( j = 0; j < height; ++j ){

        int r, g, b;
        float sumR, sumG, sumB;
        sumR = 0.0f;
        sumG = 0.0f;
        sumB = 0.0f;

        for( ii = -pixel; ii <= pixel; ii++ ){
          for( jj = -pixel; jj <= pixel; jj++ ){

            if( ( i + ii ) < 0 || width  <= ( i + ii ) ||
                ( j + jj ) < 0 || height <= ( j + jj ) ){
              continue;
            }

            int bitmapColor = pixels[( ( i + ii ) + ( j + jj ) * width )];

            r = Color.red( bitmapColor );
            g = Color.green( bitmapColor );
            b = Color.blue( bitmapColor );

            sumR += (float)r;
            sumG += (float)g;
            sumB += (float)b;
          }
        }

        int rr, gg, bb;
        rr = (int)( sumR / Math.pow( ( 1 + ( 2 * pixel ) ), 2 ) );
        gg = (int)( sumG / Math.pow( ( 1 + ( 2 * pixel ) ), 2 ) );
        bb = (int)( sumB / Math.pow( ( 1 + ( 2 * pixel ) ), 2 ) );

        Boolean flg = false;

        if( range > 0 ){
          if( lineFlg == 1 ){
            if( !( i < ( ( width / 2 ) + range ) && ( ( width / 2 ) - range ) < i ) ){
               flg = true;
            }
            
            if( ( ( width / 2 ) - ( range * 2 ) )         <= i && i < ( ( width / 2 ) - range - ( range / 2 ) ) ||
                ( ( width / 2 ) + range + ( range / 2 ) ) <= i && i < ( ( width / 2 ) + ( range * 2 ) ) ){
              pixel = 2;
            } else if( ( ( width / 2 ) - range - ( range / 2 ) ) <= i && i < ( ( width / 2 ) - range ) ||
                       ( ( width / 2 ) + range )                 <= i && i < ( ( width / 2 ) + range + ( range / 2 ) ) ){
              pixel = 1;
            } else {
              pixel = 3;
            }
          } else {
            if( !( j < ( ( height / 2 ) + range ) && ( ( height / 2 ) - range ) < j ) ){
               flg = true;
            }
            
            if( ( ( height / 2 ) - ( range * 2 ) )         <= j && j < ( ( height / 2 ) - range - ( range / 2 ) ) ||
                ( ( height / 2 ) + range + ( range / 2 ) ) <= j && j < ( ( height / 2 ) + ( range * 2 ) ) ){
              pixel = 2;
            } else if( ( ( height / 2 ) - range - ( range / 2 ) ) <= j && j < ( ( height / 2 ) - range ) ||
                       ( ( height / 2 ) + range )                 <= j && j < ( ( height / 2 ) + range + ( range / 2 ) ) ){
              pixel = 1;
            } else {
              pixel = 3;
            }
          }
        } else {
          flg = true;
        }

        if( flg == true ){
          pixels[( i + j * width )] = Color.rgb( rr, gg, bb );
        }
      }
    }

    bitmap.setPixels( pixels, 0, width, 0, 0, width, height );

    return bitmap;
  }

ミニチュア風 オリジナル:
f:id:masugata:20110519154521:image:medium
ミニチュア風 縦(違いは詳細で見てください):
f:id:masugata:20110519154530:image:medium
ミニチュア風 横(違いは詳細で見てください):
f:id:masugata:20110519154508:image:medium
ミニチュア風 縦 ぼかしのみ(違いは詳細で見てください):
f:id:masugata:20110519154502:image:medium
ミニチュア風 横 ぼかしのみ(違いは詳細で見てください):
f:id:masugata:20110519154457:image:medium


本当だったら被写体を自動的に検出してぼかしを入れないとか高度な実装したいんですけどね。。。まだまだ未熟。_| ̄|○

Android NDK(JNI - Java Native Interface)による処理の高速化

Android NDK(JNI - Java Native Interface)による処理の高速化に挑戦。
ここではモザイク処理と魚眼レンズ風処理を対象に画像を加工。

まずは新規プロジェクトを作成します。

プロジェクト名  :「exampleAndroidNDK」と入力
ビルド・ターゲット:「Android2.2」にチェックをつける
アプリケーション名:「example Android NDK」と入力
パッケージ名   :「com.example.nativeEffect」と入力
Create Activity  : チェックボタンにチェックをつけて「nativeEffectActivity」と入力
Min SDK Version  :「8」と入力

レイアウトの XML を以下のように編集します。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <ImageView  
      android:id="@+id/imageview_id"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:src="@drawable/original"
      />
</LinearLayout>

プログラム・ファイルを以下のように編集します。

package com.example.nativeEffect;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;

public class nativeEffectActivity extends Activity implements OnClickListener {

    private int flg = 0;

    static {
      System.loadLibrary( "nativeEffect" );
    }
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate( Bundle savedInstanceState ){
        super.onCreate( savedInstanceState );
        setContentView( R.layout.main );

        ImageView imageView = (ImageView)findViewById( R.id.imageview_id );
        imageView.setOnClickListener( this );
    }
    
    public void onClick( View view ){
      ImageView imageView = (ImageView)findViewById( R.id.imageview_id );

      if( this.flg == 0 ){
        this.flg = 1;
        imageView.setImageBitmap( this.effectPixelizationNative( BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true ) ) );
      } else if( this.flg == 1 ){
        this.flg = 2;
        imageView.setImageBitmap( this.effectFisheyeNative( BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true ) ) );
      } else {
        this.flg = 0;
        imageView.setImageResource( R.drawable.original );
      }
    }

    private native int nativeEffectPixelization( int [] pixels, int width, int height );
    private Bitmap effectPixelizationNative( Bitmap bitmap ){

      if( bitmap == null ){
        bitmap = BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true );
      }

      if( bitmap == null ){
        return bitmap;
      }

      if( bitmap.isMutable( ) != true ){
        bitmap = bitmap.copy( Bitmap.Config.ARGB_8888, true );
      }

      int height   = bitmap.getHeight( );
      int width    = bitmap.getWidth( );
      int[] pixels = new int[( width * height )];
      bitmap.getPixels( pixels, 0, width, 0, 0, width, height );

      int result = nativeEffectPixelization( pixels, width, height ); 
      Log.d( "DEBUG", "result=" + result );

      bitmap.setPixels( pixels, 0, width, 0, 0, width, height );

      return bitmap;
    }
    
    private native int nativeEffectFisheye( int [] pixelsSrc, int [] pixelsDest, int width, int height );
    private Bitmap effectFisheyeNative( Bitmap bitmap ){

      if( bitmap == null ){
        bitmap = BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true );
      }

      if( bitmap == null ){
        return bitmap;
      }

      if( bitmap.isMutable( ) != true ){
        bitmap = bitmap.copy( Bitmap.Config.ARGB_8888, true );
      }

      int height   = bitmap.getHeight( );
      int width    = bitmap.getWidth( );
      int[] pixelsSrc  = new int[( width * height )];
      int[] pixelsDest = new int[( width * height )];
      bitmap.getPixels( pixelsSrc, 0, width, 0, 0, width, height );

      int result = nativeEffectFisheye( pixelsSrc, pixelsDest, width, height ); 
      Log.d( "DEBUG", "result=" + result );

      bitmap.setPixels( pixelsDest, 0, width, 0, 0, width, height );

      return bitmap;
    }
}

System.loadLibraryとnativeというキーワードがポイントです(ぉ


次からはコマンドラインによる作業です。
Windows環境だとCygwinを導入しないといけないようなので作業はIntel Macで行いました。
Cygwinを導入するくらいだったらVMware Playerを使ってLinuxを導入するよ。。。_| ̄|○


事前にAndroid NDKをダウンロードしておいてください。
自分の環境では/eclipse/android_ndk以下にファイル群を展開しているので適時読み替えてください。


まずはプロジェクトのルート・ディレクトリに移動してjniフォルダを作成します。
自分の環境では/eclipse/workspace/exampleAndroidNDK/がプロジェクトのルート・ディレクトリになっているので適時読み替えてください。

% cd /eclipse/workspace/exampleAndroidNDK/
% mkdir jni


次にヘッダ・ファイルを作成します。
以下のコマンドを実行すればクラス・ファイルから自動的に抽出してくれます。

% javah -classpath bin -o jni/nativeEffect.h com.example.nativeEffect.nativeEffectActivity


次にAndroid.mkとApplication.mkを以下のように作成します。

% cat jni/Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := nativeEffect
LOCAL_SRC_FILES := nativeEffect.c

include $(BUILD_SHARED_LIBRARY)
% cat jni/Application.mk
APP_PLATFORM := android-8


次にプログラム・ファイルを以下のように作成します。

% cat jni/nativeEffect.c
#include <math.h>
#include "nativeEffect.h"

JNIEXPORT jint JNICALL Java_com_example_nativeEffect_nativeEffectActivity_nativeEffectPixelization( JNIEnv *env, jobject thiz, jintArray colors, jint width, jint height ){
  
  jint *pixels = (*env)->GetIntArrayElements( env, colors, 0 );
  int i, j, ii, jj;
  int size = 10;
  
  for( i = 0; i < width; i += size ){
    for( j = 0; j < height; j += size ){
      
      int a, aa, r, rr, g, gg , b, bb, counts;
      a = aa = r = rr = g = gg = b = bb = counts = 0;
      
      for( ii = 0; ii < size; ++ii ){
        for( jj = 0; jj < size; ++jj ){
          
          if( ( i + ii ) < 0 || width  <= ( i + ii ) ||
              ( j + jj ) < 0 || height <= ( j + jj ) ){
            continue;
          }
          
          aa = pixels[( ( i + ii ) + ( j + jj ) * width )] & 0xFF000000;
          rr = pixels[( ( i + ii ) + ( j + jj ) * width )] & 0x00FF0000;
          rr = rr >> 16;
          gg = pixels[( ( i + ii ) + ( j + jj ) * width )] & 0x0000FF00;
          gg = gg >> 8;
          bb = pixels[( ( i + ii ) + ( j + jj ) * width )] & 0x000000FF;
          
          a += aa;
          r += rr;
          g += gg;
          b += bb;
          counts++;
        }
      }
      
      aa = a / counts;
      rr = r / counts;
      gg = g / counts;
      bb = b / counts;
      
      for( ii = 0; ii < size; ++ii ){
        for( jj = 0; jj < size; ++jj ){
          
          if( ( i + ii ) < 0 || width  <= ( i + ii ) ||
              ( j + jj ) < 0 || height <= ( j + jj ) ){
            continue;
          }
          
          pixels[( ( i + ii ) + ( j + jj ) * width )] = aa | ( rr << 16 ) | ( gg << 8 ) | bb;
        }
      }
    }
  }
  
  (*env)->ReleaseIntArrayElements( env, colors, pixels, 0 );
  
  return 0;
}

JNIEXPORT jint JNICALL Java_com_example_nativeEffect_nativeEffectActivity_nativeEffectFisheye( JNIEnv *env, jobject thiz, jintArray colorsSrc, jintArray colorsDest, jint width, jint height ){
  
  jint *pixelsSrc  = (*env)->GetIntArrayElements( env, colorsSrc,  0 );
  jint *pixelsDest = (*env)->GetIntArrayElements( env, colorsDest, 0 );
  int XX, YY;
  
  int indexMax = ( width * ( height -1 ) + ( width - 1 ) );
  int weight   = 40;
  double radius;
  
  if( height < width ){
    radius = width / 2;
  } else {
    radius = height / 2;
  }
  
  for( YY = 0; YY < height; ++YY ){
    for( XX = 0; XX < width; ++XX ){
      
      double rp = sqrt( (double)( pow( (double)( weight ),          2 ) +
                                  pow( (double)( XX - width  / 2 ), 2 ) +
                                  pow( (double)( YY - height / 2 ), 2 ) ) );
      
      int XXX = (int)( ( rp * ( XX - width  / 2 ) ) / radius + width  / 2 );
      int YYY = (int)( ( rp * ( YY - height / 2 ) ) / radius + height / 2 );
      
      int srcIndex1  = ( width * YYY + XXX );
      int srcIndex2  = srcIndex1 + 1;
      int srcIndex3  = srcIndex1 + 2;
      
      int destIndex1 = ( width * YY + XX );
      int destIndex2 = destIndex1 + 1;
      int destIndex3 = destIndex1 + 2;
      
      if( 0 <= XXX && XXX < width && 0 <= YYY && YYY < height ){
        
        if( srcIndex1 <= indexMax && destIndex1 <= indexMax ){
          pixelsDest[destIndex1] = pixelsSrc[srcIndex1];
        } else if( destIndex1 <= indexMax ){
          pixelsDest[destIndex1] = 255 | ( 0 << 16 ) | ( 0 << 8 ) | 0;
        }
        
        if( srcIndex2 <= indexMax && destIndex2 <= indexMax ){
          pixelsDest[destIndex2] = pixelsSrc[srcIndex2];
        } else if( destIndex2 <= indexMax ){
          pixelsDest[destIndex2] = 255 | ( 0 << 16 ) | ( 0 << 8 ) | 0;
        }
        
        if( srcIndex3 <= indexMax && destIndex3 <= indexMax ){
          pixelsDest[destIndex2] = pixelsSrc[srcIndex2];
        } else if( destIndex3 <= indexMax ){
          pixelsDest[destIndex3] = 255 | ( 0 << 16 ) | ( 0 << 8 ) | 0;
        }
      } else if( destIndex1 <= indexMax ){
        pixelsDest[destIndex1]   = 255 | ( 0 << 16 ) | ( 0 << 8 ) | 0;
      }
    }
  }
  
  (*env)->ReleaseIntArrayElements( env, colorsSrc,  pixelsSrc,  0 );
  (*env)->ReleaseIntArrayElements( env, colorsDest, pixelsDest, 0 );
  
  return 0;
}


次にndk-buildコマンドを実行してバイナリ・ファイルを作成します。
事前に各種コマンドへのパスを通しておいてください。

% cat ~/.bash_profile 
export PATH=$PATH:/eclipse/android_ndk:/eclipse/android_sdk/platform-tools:/eclipse/android_sdk/tools
% ndk-build
Compile thumb  : nativeEffect <= nativeEffect.c
SharedLibrary  : libnativeEffect.so
Install        : libnativeEffect.so => libs/armeabi/libnativeEffect.so
%

問題なければ上記のようなメッセージが表示されます。


最後にEclipse上からアプリケーションを実行します。
アプリケーション実行時にロード関係のエラーが出る場合はEclipseを一度終了してから確認してみてください。
リフレッシュの設定はやっているのですが、自分の環境だと上手く行かない場合が結構あったので。。。_| ̄|○


オリジナル:
f:id:masugata:20110405125239:image:medium
モザイク:
f:id:masugata:20110331141802:image:medium
魚眼レンズ風:
f:id:masugata:20110412162040:image:medium


ただ、ここまでくると何がなんだか。。。という感じです。Android開発をやっているようで違うような、みたいな。
単なるC言語での開発ではなくてJNI固有のお作法なんかを学ばないといけないし、Eclipseとの連携も中途半端すぎるし、JITが効いたらソコソコ高速に動作するし、ここまでしてやる必要あるのかな?とか思う場合もあるので、適用する場合は充分に検討した上で判断してください。。。これで本当にネタ切れ。_| ̄|○