# 画面設計書 3-スタイル変換画面

## 概要

本ドキュメントは、TF DemoアプリにおけるStylizeActivity（スタイル変換画面）の画面設計書である。カメラプレビューを表示し、芸術的スタイル変換（Neural Style Transfer）を適用する画面について記述する。

### 本画面の処理概要

**業務上の目的・背景**：TensorFlowのNeural Style Transferモデルのオンデバイス推論をデモンストレーションするために本画面が必要である。"A Learned Representation For Artistic Style"（arXiv:1610.07629）に基づくモデルを使用し、カメラプレビュー映像に対してリアルタイムで芸術的スタイルを適用する。26種類のスタイル画像から選択・ブレンドが可能。

**画面へのアクセス方法**：Androidランチャーから直接起動される。AndroidManifest.xmlにてランチャーActivityとして登録されている。

**主要な操作・処理内容**：
1. カメラプレビューの表示（Camera2 APIまたは旧Camera APIによるフレーム取得）
2. スタイル画像グリッド（GridView）からスタイルを選択・スライダー操作でブレンド比率を調整
3. カメラフレームのYUV→RGB→float変換、リサイズ・クロップ処理（可変サイズ: 128/192/256/384/512/720）
4. TensorFlowInferenceInterfaceを通じたstylize_quantized.pbモデルによるスタイル変換推論
5. 変換後画像のオーバーレイ表示
6. サイズ変更ボタンによる処理解像度の切り替え
7. 保存ボタンによるスタイル変換済み画像のSDカードへの保存

**画面遷移**：Androidランチャーから起動される。他の画面への遷移機能は持たない。CameraActivity（抽象基底クラス）を継承し、CameraConnectionFragmentまたはLegacyCameraConnectionFragmentをカメラプレビュー表示に使用する。

**権限による表示制御**：カメラ権限（CAMERA）とストレージ権限（WRITE_EXTERNAL_STORAGE）が必要。Android TVではUIが適応的に変更される（スタイルセレクターのレイアウト調整、ボタン非表示）。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 52 | 画像変換操作（Image Operations） | 主機能 | カメラフレームの画像リサイズ・クロップ・色空間変換を行いスタイル変換モデル入力画像を生成 |
| 81 | TFLite推論エンジン | 主機能 | TensorFlowInferenceInterfaceを通じてstylize_quantized.pbモデルによるNeural Style Transfer推論を実行 |
| 62 | SavedModel保存 | 補助機能 | stylize_quantized.pbモデルファイルの読み込み（事前保存済みモデルの利用） |
| 5 | カメラベース画面（抽象） | 主機能 | CameraActivityを継承しカメラプレビュー・権限管理・フレーム処理の共通基盤機能を利用 |
| 6 | カメラ接続フラグメント | 補助機能 | Camera2 APIによるカメラプレビュー表示をCameraConnectionFragmentに委譲 |
| 7 | レガシーカメラ接続フラグメント | 補助機能 | Camera2非対応デバイスでのフォールバックとしてLegacyCameraConnectionFragmentを利用 |

## 画面種別

リアルタイム処理画面（カメラプレビュー＋スタイル変換＋スタイル選択UI）

## URL/ルーティング

Androidネイティブアプリのため、URLベースのルーティングは存在しない。パッケージ: `org.tensorflow.demo`、クラス: `StylizeActivity`。

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 説明 |
|--------|----------|---------|------|
| カメラプレビューフレーム | 入力 | YUV_420_888 / YUV420SP | カメラから取得される生の画像フレーム（1280x720推奨） |
| スタイル選択値 | 入力 | float[26] | 各スタイルのブレンド比率（0.0-1.0、合計1.0に正規化） |
| 処理解像度 | 入力 | int | 128/192/256/384/512/720から選択 |
| RGB変換済みBitmap | 中間 | Bitmap (ARGB_8888) | YUVからRGBに変換されたフルサイズBitmap |
| floatValues | 中間 | float[] | 0.0-1.0に正規化されたRGBピクセル値配列 |
| スタイル変換済み画像 | 出力 | Bitmap | スタイル適用後のBitmap画像 |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| カメラプレビュー | TextureView | リアルタイムカメラプレビュー映像 |
| スタイル変換結果 | OverlayView (debug_overlay) | スタイル適用後の画像をオーバーレイ表示 |
| スタイルグリッド | GridView (grid_layout) | 26種類のスタイル画像をサムネイルグリッドで表示。各ImageSliderにブレンド比率のスライダー付き |
| サイズボタン | Button | 処理解像度を変更するボタン（表示: 現在のサイズ値） |
| 保存ボタン | Button | スタイル変換済み画像を保存するボタン（表示: "save"） |

## イベント仕様

### 1-スタイル選択・ブレンドイベント

GridView上のImageSliderをタッチ操作することでスタイルのブレンド比率を調整する。

処理フロー:
1. ACTION_DOWNでタッチ位置のImageSliderを特定しハイライト表示
2. ACTION_MOVEで指の位置に応じてスライダー値（0.0-1.0）を計算
3. setStyle()で選択スライダーの値を更新
4. NORMALIZE_SLIDERS=trueの場合、他のスライダーの値を自動調整して合計が1.0になるよう正規化
5. styleVals配列を更新（推論入力用、合計1.0に正規化済み）

### 2-カメラフレーム取得・スタイル変換イベント

処理フロー:
1. desiredSizeが変更されていた場合、バッファを再初期化
2. YUV→RGB変換後、croppedBitmapにリサイズ・クロップ
3. バックグラウンドスレッドでstylizeImage()を実行
4. stylizeImage(): Bitmap→intValues→floatValues変換 → TF feed(input, style_num) → run → fetch → floatValues→intValues→Bitmap変換
5. textureCopyBitmapに結果をコピー、requestRender()で再描画

### 3-サイズ変更ボタン押下イベント

サイズボタンを押すと、desiredSizeがSIZES配列（128/192/256/384/512/720）を循環する。次フレーム処理時にバッファが再初期化される。

### 4-保存ボタン押下イベント

保存ボタンを押すと、textureCopyBitmapを `/sdcard/tensorflow/stylized{frameNum}.png` に保存し、Toastで保存先パスを表示する。

### 5-Android TVキー操作イベント

D-padの方向キーでスタイルグリッド内を移動し、選択スタイルを変更する。

## データベース更新仕様

### 操作別データベース影響一覧

本画面はデータベースを使用しない。

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| なし | なし | なし | データベース操作なし |

## メッセージ仕様

| メッセージID | メッセージ内容 | 種別 | 表示条件 |
|-------------|--------------|------|---------|
| MSG-01 | "Saved image to: /sdcard/tensorflow/stylized{N}.png" | 情報 | 画像保存成功時 |
| MSG-02 | "Camera AND storage permission are required for this demo" | 警告 | 権限未付与の場合 |

## 例外処理

| 例外状態 | 処理内容 |
|---------|---------|
| スタイル画像読み込み失敗 | Logger.e()でエラーログ出力、nullビットマップを返却 |
| カメラ権限未付与 | 権限リクエストダイアログを表示 |

## 備考

- モデルファイル: `stylize_quantized.pb`（assetsディレクトリに配置）
- スタイル画像: `thumbnails/style{0-25}.jpg`（assetsディレクトリに配置）
- スタイル数: 26（NUM_STYLES=26）
- デフォルト処理解像度: 256
- TFノード: 入力=`input`、スタイル=`style_num`、出力=`transformer/expand/conv3/conv/Sigmoid`
- レイアウト: `activity_camera.xml`（CameraActivity）+ `camera_connection_fragment_stylize.xml`（Fragment）
- Android TV対応: UIモード判定によりGridViewのレイアウトを動的に調整

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | StylizeActivity.java（内部クラス） | `tensorflow/tools/android/test/src/org/tensorflow/demo/StylizeActivity.java` | ImageSliderクラス（204-259行目）: スタイル選択用のカスタムImageView、value/hilightedフィールド |
| 1-2 | StylizeActivity.java（内部クラス） | 同上 | ImageGridAdapter（261-356行目）: スタイルグリッドのアダプタ、sizeButton/saveButton含む |

**読解のコツ**: ImageSliderはImageViewを拡張し、value（0.0-1.0）をオーバーレイ描画でスライダーとして表現する。onDraw()で黒色の半透明矩形と白線を描画する仕組みを理解すること。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | StylizeActivity.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/StylizeActivity.java` | onPreviewSizeChosen()（358-411行目）: TFInferenceInterface初期化、GridView/Adapter設定、Android TV対応 |

**主要処理フロー**:
1. **365行目**: TensorFlowInferenceInterfaceの初期化
2. **385-388行目**: GridViewの初期化とgridTouchAdapterの設定
3. **391-408行目**: Android TV対応のレイアウト調整
4. **410行目**: デフォルトスタイル（items[0]）を値1.0で設定

#### Step 3: スタイル変換処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | StylizeActivity.java | 同上 | processImage()（486-531行目）: バッファ初期化→RGB変換→クロップ→バックグラウンド推論 |
| 3-2 | StylizeActivity.java | 同上 | stylizeImage()（533-578行目）: ピクセルデータ変換→TF feed/run/fetch→結果Bitmapへの書き戻し |

**主要処理フロー（stylizeImage）**:
1. **535行目**: Bitmap→intValues変換
2. **552-557行目**: intValues→floatValues変換（0.0-1.0正規化）
3. **562-563行目**: TF feed: inputノードにfloatValues、style_numノードにstyleVals
4. **566行目**: TF run: outputノードの計算実行
5. **567行目**: TF fetch: outputノードからfloatValuesに結果取得
6. **569-575行目**: floatValues→intValues→Bitmap書き戻し

### プログラム呼び出し階層図

```
StylizeActivity (extends CameraActivity)
    |
    +-- onPreviewSizeChosen()
    |       +-- TensorFlowInferenceInterface()
    |       +-- ImageGridAdapter()
    |       +-- setStyle(items[0], 1.0f)
    |
    +-- processImage()
    |       +-- resetPreviewBuffers() [サイズ変更時]
    |       +-- getRgbBytes() [YUV->RGB]
    |       +-- Canvas.drawBitmap() [クロップ]
    |       +-- runInBackground()
    |               +-- stylizeImage()
    |               |       +-- inferenceInterface.feed(INPUT_NODE)
    |               |       +-- inferenceInterface.feed(STYLE_NODE)
    |               |       +-- inferenceInterface.run()
    |               |       +-- inferenceInterface.fetch()
    |               +-- requestRender()
    |
    +-- setStyle()
    |       +-- slider.setValue()
    |       +-- 他スライダーの正規化調整
    |       +-- styleVals[]更新
    |
    +-- gridTouchAdapter.onTouch()
            +-- setStyle()
```

### データフロー図

```
[入力]                        [処理]                              [出力]

カメラフレーム ------> YUV→RGB変換 -------> クロップ -------> stylizeImage()
(YUV_420_888)        (ImageUtils)        (変換行列)        (TF Inference)
  1280x720                                desiredSize            |
                                                                 v
スタイル選択 -------> styleVals[26] -----------------> TF feed(style_num)
(GridView操作)      (正規化済み)                             |
                                                             v
                                                    スタイル変換済みBitmap
                                                             |
                                                    OverlayView表示
                                                    /sdcard保存(任意)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| StylizeActivity.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/StylizeActivity.java` | ソース | スタイル変換画面の主要Activity |
| CameraActivity.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/CameraActivity.java` | ソース | カメラ処理の抽象基底クラス |
| TensorFlowInferenceInterface | `org.tensorflow.contrib.android` | ライブラリ | TensorFlow推論インターフェース |
| camera_connection_fragment_stylize.xml | `tensorflow/tools/android/test/res/layout/camera_connection_fragment_stylize.xml` | レイアウト | スタイル変換用Fragmentレイアウト |
| stylize_quantized.pb | `assets/stylize_quantized.pb` | モデル | Neural Style Transferモデル |
| thumbnails/style{0-25}.jpg | `assets/thumbnails/` | データ | 26種類のスタイルサムネイル画像 |
