<?xml version="1.0" encoding="UTF-8" ?><rdf:RDF 
  xmlns="http://purl.org/rss/1.0/"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xml:lang="ja">
  <channel rdf:about="http://w.atwiki.jp/tdnki/">
    <title>tdnki @ ウィキ</title>
    <link>http://w.atwiki.jp/tdnki/</link>
    <atom:link href="https://w.atwiki.jp/tdnki/rss10.xml" rel="self" type="application/rss+xml" />
    <atom:link rel="hub" href="https://pubsubhubbub.appspot.com" />
    <description>tdnki @ ウィキ</description>

    <dc:language>ja</dc:language>
    <dc:date>2014-02-05T11:20:39+09:00</dc:date>
    <utime>1391566839</utime>

    <items>
      <rdf:Seq>
                <rdf:li rdf:resource="https://w.atwiki.jp/tdnki/pages/51.html" />
                <rdf:li rdf:resource="https://w.atwiki.jp/tdnki/pages/49.html" />
                <rdf:li rdf:resource="https://w.atwiki.jp/tdnki/pages/48.html" />
                <rdf:li rdf:resource="https://w.atwiki.jp/tdnki/pages/47.html" />
                <rdf:li rdf:resource="https://w.atwiki.jp/tdnki/pages/45.html" />
                <rdf:li rdf:resource="https://w.atwiki.jp/tdnki/pages/44.html" />
                <rdf:li rdf:resource="https://w.atwiki.jp/tdnki/pages/43.html" />
                <rdf:li rdf:resource="https://w.atwiki.jp/tdnki/pages/42.html" />
                <rdf:li rdf:resource="https://w.atwiki.jp/tdnki/pages/41.html" />
                <rdf:li rdf:resource="https://w.atwiki.jp/tdnki/pages/40.html" />
              </rdf:Seq>
    </items>
	
		
    
  </channel>
    <item rdf:about="https://w.atwiki.jp/tdnki/pages/51.html">
    <title>Android/TIPS</title>
    <link>https://w.atwiki.jp/tdnki/pages/51.html</link>
    <description>
      ***&amp;spanclass(headline){ライブラリにjavadocを関連付ける}
[[Android]]プロジェクトのlibsフォルダに配置したライブラリは、自動的にビルドパス(Android Private Libraries)に追加されるが、ソースやjavadocのロケーションを変更できない。
回避策は以下。

1. ソースとjavadocを適当な場所に置く。

2. ライブラリのファイル名(拡張子.jarを含む)に.propertiesを付加したテキストファイルを作り、ライブラリと同階層に置く。
(ex.
libs
├　library.jar
├　library.jar.properties
├　src
│　└ library_sources.jar
└　doc
　　└ library_javadoc.jar

3. propertiesファイルに、ソースとjavadocのパスをそれぞれ&quot;src&quot;,&quot;doc&quot;で指定する。
library.jar.properties
 src=src/library_sources.jar
 doc=doc/library_javadoc.jar

4. プロジェクトを開きなおす。
反映されるタイミングがよくわからないが、プロジェクトを開きなおせば確実。    </description>
    <dc:date>2014-02-05T11:20:39+09:00</dc:date>
    <utime>1391566839</utime>
  </item>
    <item rdf:about="https://w.atwiki.jp/tdnki/pages/49.html">
    <title>ComicFinder/OpenGLDrawing</title>
    <link>https://w.atwiki.jp/tdnki/pages/49.html</link>
    <description>
      ***&amp;spanclass(headline){7. OpenGLによる描画}
これまでの実装では、画像処理から描画までをメインスレッドでシーケンシャルに実行しているだけなので、FPSが安定しない。
描画をOpenGLに委譲することで、FPSの安定化を図っていく。

***&amp;spanclass(bold){7-1. }    </description>
    <dc:date>2013-10-27T13:42:12+09:00</dc:date>
    <utime>1382848932</utime>
  </item>
    <item rdf:about="https://w.atwiki.jp/tdnki/pages/48.html">
    <title>ComicFinder/OptimizationNeon</title>
    <link>https://w.atwiki.jp/tdnki/pages/48.html</link>
    <description>
      ***&amp;spanclass(headline){6. 画像処理の高速化(NEON編)}
NEON(ARMのCPU拡張命令)を使用して、さらなる高速化を図る。

***&amp;spanclass(bold){6-1. 準備}
NEONを有効にする。

[[Android]].mk
 LOCAL_ARM_NEON := true

これだけだと、NEONはv7aでしかサポートしていない、とビルドエラーが出るので
v7a向けのビルドを明示する。

Application.mk
 APP_ABI := armeabi-v7a

Android.mk
 ifeq ($(TARGET_ARCH_ABI), armeabi-v7a)
     LOCAL_ARM_NEON  := true
     LOCAL_CFLAGS += -DENABLE_NEON
 endif

もし APP_ABI をデフォルトの armeabi に戻してもビルドエラーとならないよう、TARGET_ARCH_ABI を見るようにした。
LOCAL_CFLAGS に渡したのは、今後、ビルド対象によってコード側も ifdef で切り分けるための define なので、
わかりやすい名前なら何でも良い。

ちなみに、これだけでかなり最適化がかかり、速くなってしまった。
40ms → 30ms

***&amp;spanclass(bold){6-2. 方針}
NEONでは64bitか128bitのベクタを使用できるので、unsigned charのピクセルデータは16個を並列処理できる。
ただし、今回はSobelフィルタの途中計算で16bit精度が必要となるので、8個ずつループを回して処理していく。

画像幅が8で割り切れない場合は端数処理が必要なので、水平方向のループカウンタjを外に出した。

[[ComicFinder]].cpp
 for (int i = 0; i &lt; height; i++) {
     int j = 0;
 #ifdef ENABLE_NEON
     for ( ; j &lt; width-7; j+=8) {
         // NEONコード
 
     }
 #endif
     for     </description>
    <dc:date>2013-10-24T14:07:32+09:00</dc:date>
    <utime>1382591252</utime>
  </item>
    <item rdf:about="https://w.atwiki.jp/tdnki/pages/47.html">
    <title>ComicFinder/Optimization</title>
    <link>https://w.atwiki.jp/tdnki/pages/47.html</link>
    <description>
      ***&amp;spanclass(headline){5. 画像処理の高速化}
30fps(33ms)を目指して高速化していく。

現時点で1フレームの画像処理にかかる時間は80ms。
画像処理とは別に、描画にすでに10ms消費しているので、画像処理は23ms以下を目標とする。

***&amp;spanclass(bold){5-1. ループ統合}
画像の3値化と輪郭抽出で、2回に分けて全ピクセルをなめているが、
これは統合可能。

[[ComicFinder]].cpp
 int lum, fx, fy, im, ip, jm, jp;
 for (int i = 0; i &lt; height; i++) {
     im = i-1;
     ip = i+1;
     im = im &lt; 0 ? 0 : im;
     ip = ip &gt; height-1 ? height-1 : ip;
 
     for (int j = 0; j &lt; width; j++) {
         lum = p_src[i*width+j];
 
         if (lum &lt; threshold_black_and_gray) {
             lum = 0x00;
         }
         else if (lum &lt; threshold_gray_and_white) {
             lum = ((i+j) % 2) == 0 ? 0x00 : 0xff;
         }
         else {
             lum = 0xff;
         }
 
         if (lum != 0x00) {
             jm = j-1;
             jp = j+1;
             jm = jm &lt; 0 ? 0 : jm;
             jp = jp &gt; width-1 ? width-1 : jp;
 
             fx = 0;
             fx += p_src[im*width+jm] * -1;
              </description>
    <dc:date>2013-10-21T00:05:50+09:00</dc:date>
    <utime>1382281550</utime>
  </item>
    <item rdf:about="https://w.atwiki.jp/tdnki/pages/45.html">
    <title>ComicFinder/ImageProcessing</title>
    <link>https://w.atwiki.jp/tdnki/pages/45.html</link>
    <description>
      ***&amp;spanclass(headline){4. 画像処理}
漫画風の画像処理を実装していく。

***&amp;spanclass(bold){4-1. 三値化}
グレースケールの画像を、白、黒、グレーの三値に変換する。
閾値は動かしながら良いものを選ぶ。

[[ComicFinder]].cpp
 const int threshold_black_and_gray = 60;
 const int threshold_gray_and_white = 120;
 
 int lum;
 for (int k = 0; k &lt; width*height; k++) {
     lum = p_src[k];
     if (lum &lt; threshold_black_and_gray) {
         lum = 0x00;
     }
     else if (lum &lt; threshold_gray_and_white) {
         lum = 0x80;
     }
     else {
         lum = 0xff;
     }
 
     p_dst[k*4+0] = p_dst[k*4+1] = p_dst[k*4+2] = lum;
     p_dst[k*4+3] = 0xff;
 }

より漫画っぽくするために、グレー(128/255)を、白と黒の市松模様で表現する。
グレーと判定されたピクセルのx座標とy座標のパリティが一致したら黒、不一致なら白とした。

ComicFinder.cpp
 for (int i = 0; i &lt; height; i++) {
     for (int j = 0; j &lt; width; j++) {
         lum = p_src[i*width+j];
 
         if (lum &lt; threshold_black_and_gray) {
             lum = 0x00;
         }
         else if (lum &lt; threshold_gray_and_white) {
             lum = ((i+j) %     </description>
    <dc:date>2013-09-04T01:51:39+09:00</dc:date>
    <utime>1378227099</utime>
  </item>
    <item rdf:about="https://w.atwiki.jp/tdnki/pages/44.html">
    <title>ComicFinder/FasterDrawing</title>
    <link>https://w.atwiki.jp/tdnki/pages/44.html</link>
    <description>
      ***&amp;spanclass(headline){3. 描画の高速化}
前回、Canvas#drawBitmap()が意外に遅いことがわかってしまった。

***&amp;spanclass(bold){3-1. drawBitmap(Bitmap, float, float, Paint)を使う}
このメソッドに、今まではintの配列を渡していたが、Bitmapを渡すオーバーロードを呼んでみたところ、int[]に比べて3倍ほど高速であった。
そこで、描画データはBitmapで持つように修正する。

MainActivity.java
 @Override
 protected void onResume() {
     ：
     ：
     // 描画用Bitmap
     previewBitmap = Bitmap.createBitmap(previewSize.width, previewSize.height, Bitmap.Config.ARGB_8888);
     ：
     ：
 }
 
 @Override
 protected void onPause() {
     super.onPause();
 
     if (camera != null) {
         camera.stopPreview();
         camera.release();
     }
 
     if (previewBitmap != null) {
         previewBitmap.recycle();
     }
 }

***&amp;spanclass(bold){3-2. nativeコードでBitmapを扱う}
int[]からBitmapを生成する処理もそこそこ重く、描画データをBitmapに変更することで浮くであろうマージンを食い潰してしまう。

幸いnativeからBitmapのピクセルデータに触る方法があるので、Bitmapをそのまま渡し、書き換える形に変更する。
C++がJavaのクラスを意識するのは気持ち悪いが、速度にはかえられない。

[[ComicFinder]].hpp
 JNIEXPORT bool JNICALL J    </description>
    <dc:date>2013-08-31T23:32:14+09:00</dc:date>
    <utime>1377959534</utime>
  </item>
    <item rdf:about="https://w.atwiki.jp/tdnki/pages/43.html">
    <title>ComicFinder/NativeCode</title>
    <link>https://w.atwiki.jp/tdnki/pages/43.html</link>
    <description>
      ***&amp;spanclass(headline){2. nativeコードへの移行}
前回のコードによる描画処理には、Xperia VLで50ms～70ms程度かかっていた(15～20fps)。
これからさらに重い画像処理を追加しながらも、30fps程度は実現したいため、
C/C++による実装に切り替えて高速化を図っていく。

前回、Javaで書いたpreviewBufferRgbaを書き込む処理を、C++で置き換えることを目標とする。

***&amp;spanclass(bold){2-1. nativeサポートの追加}
プロジェクト上で右クリックし、[[[Android]] Tools] &gt; [Add Native Support...] を選択する。
適当なライブラリ名を入力して決定すると、プロジェクトルートにjniフォルダが作成される。
以降、ツールバーのとんかちのアイコン&amp;ref(hammer.png)や、プロジェクトのビルドのタイミングでnativeコードがビルドされる。

早速ビルドしてみようととんかちを押すと、次の警告が出る。
 APP_PLATFORM android-** is larger than android:minSdkVersion ** in ./AndroidManifest.xml
自動で設定されたnativeコードのターゲットが、アプリ側で設定したminSdkVersionより大きいことを示す警告で、
アプリ側ではエラーとして扱われる。
jniフォルダにApplication.mkファイルを追加し、minSdkVersionを超えない値をターゲットとすることで解決できる。

Application.mk
 APP_PLATFORM := android-8

***&amp;spanclass(bold){2-2. native関数を呼ぶ準備}
関数を呼びたいクラスに、関数定義と、staticイニシャライザでsoを読み込む処理を追加する。

MainActivity.java
 private native boolean processImage(byte[] src, int[] dst, int width, int height);
 
 static {
     System    </description>
    <dc:date>2013-08-31T21:26:34+09:00</dc:date>
    <utime>1377951994</utime>
  </item>
    <item rdf:about="https://w.atwiki.jp/tdnki/pages/42.html">
    <title>ComicFinder/CameraPreview</title>
    <link>https://w.atwiki.jp/tdnki/pages/42.html</link>
    <description>
      ***&amp;spanclass(headline){1. カメラプレビューの表示}
プレビュー画像に使用されるNV21フォーマットは、輝度のみのデータを取り出しやすいこと、
最終的な画像処理にも輝度しか使用しない予定であることから、モノクロのプレビュー表示をゴールとする。

***&amp;spanclass(bold){1-1. Permissionを付加する}
AndroidManifest.xml
 &lt;uses-permission android:name=&quot;android.permission.CAMERA&quot;/&gt;

***&amp;spanclass(bold){1-2. Activityの向きを固定する}
端末の回転を考慮したくないので、Orientationはlandscape固定とする。

AndroidManifest.xml
 &lt;activity
     android:name=&quot;com.example.comicfinder.MainActivity&quot;
     android:label=&quot;@string/app_name&quot;
     android:screenOrientation=&quot;landscape&quot; &gt;
     &lt;intent-filter&gt;
         &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;
 
         &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;
     &lt;/intent-filter&gt;
 &lt;/activity&gt;

***&amp;spanclass(bold){1-3. フルスクリーン}
MainActivity.java
 @Override
 protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
 
     // setContentView()より先に呼ぶこと。
     getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCRE    </description>
    <dc:date>2013-09-04T00:20:48+09:00</dc:date>
    <utime>1378221648</utime>
  </item>
    <item rdf:about="https://w.atwiki.jp/tdnki/pages/41.html">
    <title>ComicFinder/Preparation</title>
    <link>https://w.atwiki.jp/tdnki/pages/41.html</link>
    <description>
      ***&amp;spanclass(headline){0. 準備}
以下のものをインストールする。
+Eclipse
+[[Android]] SDK
+Android NDK
Eclipseに以下のものをインストールする。
+ADT Plugin
+CDT Plugin    </description>
    <dc:date>2013-08-30T21:51:32+09:00</dc:date>
    <utime>1377867092</utime>
  </item>
    <item rdf:about="https://w.atwiki.jp/tdnki/pages/40.html">
    <title>ComicFinder</title>
    <link>https://w.atwiki.jp/tdnki/pages/40.html</link>
    <description>
      目標：C++を利用した高速な[[Android]]カメラアプリを作る。

ポイント：
1. Cameraハードウェアを利用する。
2. JNIによりJavaからC++を呼び出す。
3. NEONを使用して高速化する。

目次：
[[0. 準備&gt;ComicFinder/Preparation]]
[[1. カメラプレビューの表示&gt;ComicFinder/CameraPreview]]
[[2. nativeコードへの移行&gt;ComicFinder/NativeCode]]
[[3. 描画の高速化&gt;ComicFinder/FasterDrawing]]
[[4. 画像処理&gt;ComicFinder/ImageProcessing]]
[[5. 画像処理の高速化&gt;ComicFinder/Optimization]]
[[6. 画像処理の高速化(NEON編)&gt;ComicFinder/OptimizationNeon]]

[[7. OpenGLによる描画(作成中)&gt;ComicFinder/OpenGLDrawing]]    </description>
    <dc:date>2013-10-24T14:12:35+09:00</dc:date>
    <utime>1382591555</utime>
  </item>
  </rdf:RDF>
