# 画面設計書 1-画像分類画面

## 概要

本ドキュメントは、TF DemoアプリにおけるClassifierActivity（画像分類画面）の画面設計書である。カメラプレビューを表示し、リアルタイムでInceptionモデルによる画像分類（Image Classification）を実行する画面について記述する。

### 本画面の処理概要

**業務上の目的・背景**：TensorFlowの画像分類モデル（Inception v1）のオンデバイス推論をデモンストレーションするために本画面が必要である。モバイルデバイス上でリアルタイムにカメラプレビューから画像を取得し、機械学習モデルによる分類結果を表示することで、TensorFlowのAndroid上での動作を確認・検証する目的がある。

**画面へのアクセス方法**：Androidランチャーから直接起動される。AndroidManifest.xmlにてランチャーActivityとして登録されており、アプリアイコンをタップすることでアクセスできる。

**主要な操作・処理内容**：
1. カメラプレビューの表示（Camera2 APIまたは旧Camera APIによるフレーム取得）
2. カメラフレームのYUV→RGB変換およびリサイズ・クロップ処理（224x224ピクセルへの変換）
3. TensorFlowImageClassifierを通じたInceptionモデルによる画像分類推論の実行
4. 分類結果（ラベルと信頼度）のResultsViewへの表示
5. デバッグモード時のオーバーレイ情報（フレームサイズ、推論時間等）の表示
6. ボリュームキー等によるデバッグモードの切り替え

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

**権限による表示制御**：カメラ権限（CAMERA）とストレージ権限（WRITE_EXTERNAL_STORAGE）が必要。権限が未付与の場合、権限リクエストダイアログが表示される。権限が拒否された場合はカメラプレビューが表示されない。

## 関連機能

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

## 画面種別

リアルタイム処理画面（カメラプレビュー＋推論結果表示）

## URL/ルーティング

Androidネイティブアプリのため、URLベースのルーティングは存在しない。AndroidManifest.xmlにてランチャーActivityとして登録。パッケージ: `org.tensorflow.demo`、クラス: `ClassifierActivity`。

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 説明 |
|--------|----------|---------|------|
| カメラプレビューフレーム | 入力 | YUV_420_888 / YUV420SP | カメラから取得される生の画像フレーム（640x480推奨） |
| RGB変換済みBitmap | 中間 | Bitmap (ARGB_8888) | YUVからRGBに変換されたフルサイズBitmap |
| クロップ済みBitmap | 中間 | Bitmap (ARGB_8888) | 224x224にリサイズ・クロップされた推論入力用Bitmap |
| 分類結果リスト | 出力 | List<Classifier.Recognition> | ラベル名・信頼度・IDを含む分類結果のリスト |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| カメラプレビュー | TextureView | リアルタイムカメラプレビュー映像 |
| 分類結果 | ResultsView | 分類ラベルと信頼度のリスト表示 |
| デバッグ情報（任意） | OverlayView | フレームサイズ、クロップサイズ、回転角度、推論時間 |

## イベント仕様

### 1-カメラフレーム取得イベント

カメラからフレームが利用可能になった際（onImageAvailable / onPreviewFrame）に自動的にトリガーされる。CameraActivityの共通基盤により、フレームデータがYUVバイト配列として取得され、processImage()メソッドが呼び出される。

処理フロー:
1. getRgbBytes()によりYUV→RGB変換を実行
2. rgbFrameBitmapにRGBピクセルを設定
3. frameToCropTransformを使用してcroppedBitmap（224x224）に変換
4. バックグラウンドスレッドでclassifier.recognizeImage()を実行
5. 結果をresultsViewに設定し、画面を再描画

### 2-デバッグモード切り替えイベント

ボリュームキー（上下）、L1ボタン、またはD-padセンターキーを押下すると、デバッグモードのON/OFFが切り替わる。デバッグモードON時はオーバーレイにクロップ画像、統計情報、推論時間等が表示される。

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

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

本画面はデータベースを使用しない。全ての処理はメモリ上で完結する。

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

## メッセージ仕様

| メッセージID | メッセージ内容 | 種別 | 表示条件 |
|-------------|--------------|------|---------|
| MSG-01 | "Camera AND storage permission are required for this demo" | 警告 | カメラまたはストレージ権限が未付与の場合 |
| MSG-02 | "No Camera Detected" | エラー | 利用可能なカメラが検出されなかった場合 |

## 例外処理

| 例外状態 | 処理内容 |
|---------|---------|
| カメラ権限未付与 | 権限リクエストダイアログを表示。拒否された場合は再度リクエスト |
| カメラデバイスエラー | CameraDevice.StateCallback.onError()によりActivityを終了 |
| Camera2 API非対応 | LegacyCameraConnectionFragmentにフォールバック |
| フレーム処理中の新フレーム到着 | 処理中フラグ(isProcessingFrame)により新フレームをドロップ |

## 備考

- モデルファイル: `tensorflow_inception_graph.pb`（assetsディレクトリに配置）
- ラベルファイル: `imagenet_comp_graph_label_strings.txt`（assetsディレクトリに配置）
- 入力サイズ: 224x224、IMAGE_MEAN: 117、IMAGE_STD: 1
- レイアウト: `activity_camera.xml`（CameraActivity）+ `camera_connection_fragment.xml`（Fragment）

---

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

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

### 推奨読解順序

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

まず、推論結果のデータ構造と分類器インターフェースを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Classifier.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/Classifier.java` | Recognitionクラス（ラベル、信頼度、位置）とrecognizeImage()インターフェースを確認 |

**読解のコツ**: Classifierインターフェースがどのようなメソッド（recognizeImage, enableStatLogging, getStatString）を定義しているかを押さえることで、ClassifierActivityの処理の流れが理解しやすくなる。

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

処理の起点となるClassifierActivityの全体構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ClassifierActivity.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/ClassifierActivity.java` | モデル定数定義（66-75行目）、onPreviewSizeChosen()でのモデル初期化（104-147行目）、processImage()での推論実行（149-176行目） |

**主要処理フロー**:
1. **66-75行目**: INPUT_SIZE=224, MODEL_FILE, LABEL_FILE等のモデルパラメータ定数定義
2. **111-120行目**: TensorFlowImageClassifier.create()によるモデルの初期化
3. **129-130行目**: rgbFrameBitmapとcroppedBitmapの生成
4. **132-135行目**: frameToCropTransform（座標変換行列）の計算
5. **150-151行目**: YUV→RGBピクセル変換とクロップBitmapへの描画
6. **159-175行目**: バックグラウンドスレッドでのrecognizeImage()実行と結果表示

#### Step 3: カメラ基盤クラスを理解する

ClassifierActivityの親クラスであるCameraActivityの共通処理基盤を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | CameraActivity.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/CameraActivity.java` | onCreate()でのレイアウト設定と権限チェック（74-86行目）、setFragment()でのCamera2/Legacy分岐（352-386行目）、onImageAvailable()でのCamera2フレーム処理（155-215行目） |

**主要処理フロー**:
- **74-86行目**: onCreate()でactivity_camera.xmlを設定し、権限に応じてsetFragment()を呼び出し
- **352-386行目**: useCamera2APIフラグに基づきCameraConnectionFragmentまたはLegacyCameraConnectionFragmentを生成
- **155-215行目**: Camera2 APIからのフレーム取得、YUVデータ抽出、processImage()呼び出し
- **266-270行目**: runInBackground()によるHandlerThread経由のバックグラウンド実行

#### Step 4: カメラフラグメントを理解する

Camera2 APIを使ったカメラプレビューの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | CameraConnectionFragment.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/CameraConnectionFragment.java` | newInstance()ファクトリメソッド（309-315行目）、setUpCameraOutputs()でのプレビューサイズ決定（363-408行目）、createCameraPreviewSession()でのYUV_420_888 ImageReader設定（496-562行目） |

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

```
ClassifierActivity (extends CameraActivity)
    |
    +-- onCreate() [CameraActivity]
    |       +-- setContentView(R.layout.activity_camera)
    |       +-- setFragment()
    |               +-- chooseCamera()
    |               +-- CameraConnectionFragment.newInstance() / LegacyCameraConnectionFragment()
    |
    +-- onPreviewSizeChosen()
    |       +-- TensorFlowImageClassifier.create()
    |       +-- Bitmap.createBitmap() [rgb, cropped]
    |       +-- ImageUtils.getTransformationMatrix()
    |
    +-- processImage()
            +-- getRgbBytes() [YUV->RGB変換]
            +-- Canvas.drawBitmap() [リサイズ・クロップ]
            +-- runInBackground()
                    +-- classifier.recognizeImage(croppedBitmap)
                    +-- resultsView.setResults(results)
                    +-- requestRender()
                    +-- readyForNextImage()
```

### データフロー図

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

カメラフレーム -----> YUV→RGB変換 -----> リサイズ/クロップ -----> Inception推論
(YUV_420_888)      (ImageUtils)       (frameToCropTransform)   (TensorFlowImageClassifier)
  640x480                                  224x224                      |
                                                                       v
                                                              List<Recognition>
                                                                       |
                                                                       v
                                                              ResultsView表示
                                                              OverlayView(debug)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ClassifierActivity.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/ClassifierActivity.java` | ソース | 画像分類画面の主要Activity |
| CameraActivity.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/CameraActivity.java` | ソース | カメラ処理の抽象基底クラス |
| CameraConnectionFragment.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/CameraConnectionFragment.java` | ソース | Camera2 APIによるプレビューFragment |
| LegacyCameraConnectionFragment.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/LegacyCameraConnectionFragment.java` | ソース | 旧Camera APIによるプレビューFragment |
| TensorFlowImageClassifier.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/TensorFlowImageClassifier.java` | ソース | Inceptionモデルによる画像分類器 |
| Classifier.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/Classifier.java` | ソース | 分類器インターフェース定義 |
| ImageUtils.java | `tensorflow/tools/android/test/src/org/tensorflow/demo/env/ImageUtils.java` | ソース | 画像変換ユーティリティ |
| activity_camera.xml | `tensorflow/tools/android/test/res/layout/activity_camera.xml` | レイアウト | メインActivityレイアウト |
| camera_connection_fragment.xml | `tensorflow/tools/android/test/res/layout/camera_connection_fragment.xml` | レイアウト | カメラプレビューFragmentレイアウト |
| tensorflow_inception_graph.pb | `assets/tensorflow_inception_graph.pb` | モデル | Inception v1画像分類モデル |
| imagenet_comp_graph_label_strings.txt | `assets/imagenet_comp_graph_label_strings.txt` | データ | ImageNetラベルファイル |
